# Spring Security OAuth2 Demo
项目使用的是MySql存储, 需要先创建以下表结构:
```
CREATE SCHEMA IF NOT EXISTS `alan-oauth` DEFAULT CHARACTER SET utf8 ;
USE `alan-oauth` ;
-- -----------------------------------------------------
-- Table `alan-oauth`.`clientdetails`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `alan-oauth`.`clientdetails` (
`appId` VARCHAR(128) NOT NULL,
`resourceIds` VARCHAR(256) NULL DEFAULT NULL,
`appSecret` VARCHAR(256) NULL DEFAULT NULL,
`scope` VARCHAR(256) NULL DEFAULT NULL,
`grantTypes` VARCHAR(256) NULL DEFAULT NULL,
`redirectUrl` VARCHAR(256) NULL DEFAULT NULL,
`authorities` VARCHAR(256) NULL DEFAULT NULL,
`access_token_validity` INT(11) NULL DEFAULT NULL,
`refresh_token_validity` INT(11) NULL DEFAULT NULL,
`additionalInformation` VARCHAR(4096) NULL DEFAULT NULL,
`autoApproveScopes` VARCHAR(256) NULL DEFAULT NULL,
PRIMARY KEY (`appId`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `alan-oauth`.`oauth_access_token`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_access_token` (
`token_id` VARCHAR(256) NULL DEFAULT NULL,
`token` BLOB NULL DEFAULT NULL,
`authentication_id` VARCHAR(128) NOT NULL,
`user_name` VARCHAR(256) NULL DEFAULT NULL,
`client_id` VARCHAR(256) NULL DEFAULT NULL,
`authentication` BLOB NULL DEFAULT NULL,
`refresh_token` VARCHAR(256) NULL DEFAULT NULL,
PRIMARY KEY (`authentication_id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `alan-oauth`.`oauth_approvals`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_approvals` (
`userId` VARCHAR(256) NULL DEFAULT NULL,
`clientId` VARCHAR(256) NULL DEFAULT NULL,
`scope` VARCHAR(256) NULL DEFAULT NULL,
`status` VARCHAR(10) NULL DEFAULT NULL,
`expiresAt` DATETIME NULL DEFAULT NULL,
`lastModifiedAt` DATETIME NULL DEFAULT NULL)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `alan-oauth`.`oauth_client_details`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_client_details` (
`client_id` VARCHAR(128) NOT NULL,
`resource_ids` VARCHAR(256) NULL DEFAULT NULL,
`client_secret` VARCHAR(256) NULL DEFAULT NULL,
`scope` VARCHAR(256) NULL DEFAULT NULL,
`authorized_grant_types` VARCHAR(256) NULL DEFAULT NULL,
`web_server_redirect_uri` VARCHAR(256) NULL DEFAULT NULL,
`authorities` VARCHAR(256) NULL DEFAULT NULL,
`access_token_validity` INT(11) NULL DEFAULT NULL,
`refresh_token_validity` INT(11) NULL DEFAULT NULL,
`additional_information` VARCHAR(4096) NULL DEFAULT NULL,
`autoapprove` VARCHAR(256) NULL DEFAULT NULL,
PRIMARY KEY (`client_id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `alan-oauth`.`oauth_client_token`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_client_token` (
`token_id` VARCHAR(256) NULL DEFAULT NULL,
`token` BLOB NULL DEFAULT NULL,
`authentication_id` VARCHAR(128) NOT NULL,
`user_name` VARCHAR(256) NULL DEFAULT NULL,
`client_id` VARCHAR(256) NULL DEFAULT NULL,
PRIMARY KEY (`authentication_id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `alan-oauth`.`oauth_code`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_code` (
`code` VARCHAR(256) NULL DEFAULT NULL,
`authentication` BLOB NULL DEFAULT NULL)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `alan-oauth`.`oauth_refresh_token`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `alan-oauth`.`oauth_refresh_token` (
`token_id` VARCHAR(256) NULL DEFAULT NULL,
`token` BLOB NULL DEFAULT NULL,
`authentication` BLOB NULL DEFAULT NULL)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
```
然后在`oauth_client_details`表中插入记录:
```
# client_id, resource_ids, client_secret, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove
'client', NULL, 'secret', 'app', 'authorization_code', 'http://www.baidu.com', NULL, NULL, NULL, NULL, NULL
```
这时就可以访问授权页面了:
```
localhost:8080/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://www.baidu.com
```
访问时Spring让你登陆,随便输入一个用户名密码即可。
**注意, 如果每次登陆时输入的用户名不一样,那么Spring Security会认为是不同的用户,因此访问/token/authorize会再次显示授权页面。如果用户名一致, 则只需要授权一次**
数据库连接信息在`application.properties`中配置。
Spring Cloud Security OAuth2 是 Spring 对 OAuth2 的开源实现,优点是能与Spring Cloud技术栈无缝集成,如果全部使用默认配置,开发者只需要添加注解就能完成 OAuth2 授权服务的搭建。
# 博文
## 1. 添加依赖
授权服务是基于Spring Security的,因此需要在项目中引入两个依赖:
```
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
```
前者为 Security,后者为Security的OAuth2扩展。
## 2. 添加注解和配置
在启动类中添加`@EnableAuthorizationServer`注解:
```
@SpringBootApplication
@EnableAuthorizationServer
public class AlanOAuthApplication {
public static void main(String[] args) {
SpringApplication.run(AlanOAuthApplication.class, args);
}
}
```
完成这些我们的授权服务最基本的骨架就已经搭建完成了。但是要想跑通整个流程,我们必须分配 `client_id`, `client_secret`才行。Spring Security OAuth2的配置方法是编写`@Configuration`类继承`AuthorizationServerConfigurerAdapter`,然后重写`void configure(ClientDetailsServiceConfigurer clients)`方法,如:
```java
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory() // 使用in-memory存储
.withClient("client") // client_id
.secret("secret") // client_secret
.authorizedGrantTypes("authorization_code") // 该client允许的授权类型
.scopes("app"); // 允许的授权范围
}
```
## 3. 授权流程
访问授权页面:
```
localhost:8080/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://www.baidu.com
```
此时浏览器会让你输入用户名密码,这是因为 Spring Security 在默认情况下会对所有URL添加Basic Auth认证。默认的用户名为`user`, 密码是随机生成的,在控制台日志中可以看到。
![oauth2](http://img.blog.csdn.net/20160914172241289)
画风虽然很简陋,但是基本功能都具备了。点击`Authorize`后,浏览器就会重定向到百度,并带上`code`参数:
![这里写图片描述](http://img.blog.csdn.net/20160914172412190)
拿到`code`以后,就可以调用
```
POST/GET http://client:secret@localhost:8080/oauth/token
```
来换取`access_token`了:
```
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'grant_type=authorization_code&code=Li4NZo&redirect_uri=http://www.baidu.com' "http://client:secret@localhost:8080/oauth/token"
```
> 注意,URL中的client为上文中通过`ClientDetailsServiceConfigurer`类指定的clientId。由于authorization_code�