一、最简单认证服务器

1. pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.1.0.RELEASE</version>
</dependency>

2. 配置application.yml

security:
  oauth2:
    client:
      client-id: clientId
      client-secret: clientSecret
      scope: scope1, scope2, scope3, scope4
      registered-redirect-uri: http://www.baidu.com
spring: security: user: name: admin password: admin

3. 开启@EnableAuthorizationServer,同时开启SpringSecurity用户登录认证

@SpringBootApplication
@EnableAuthorizationServer
public class SpringBootTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootTestApplication.class, args);
    }

    @Bean
    public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter() {
        return new WebSecurityConfigurerAdapter() {
            @Override
            public void configure(HttpSecurity httpSecurity) throws Exception {
                httpSecurity.formLogin().and().csrf().disable(); 
       }
     };
   }
}

4. 测试

(1)密码模式和客户端模式直接通过单元测试就可以完成

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringBootTestApplicationTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void token_password() {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("grant_type", "password");
        params.add("username", "admin");
        params.add("password", "admin");
        params.add("scope", "scope1 scope2");
        String response = restTemplate.withBasicAuth("clientId", "clientSecret").
                postForObject("/oauth/token", params, String.class);
        System.out.println(response);
    }

    @Test
    public void token_client() {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("grant_type", "client_credentials");
        String response = restTemplate.withBasicAuth("clientId", "clientSecret").
                postForObject("/oauth/token", params, String.class);
        System.out.println(response);
    }
    
}

(2)授权码验证模式

  • 访问 http://127.0.0.1:8080/oauth/authorize?client_id=clientId&response_type=code,跳转到SpringSecurity默认的登录页面:
    SpringBoot实现OAuth2认证服务器
  • 输入用户名/密码:admin/admin,点击登录后跳转到确认授权页面:
    SpringBoot实现OAuth2认证服务器

     

  • 至少选中一个,然后点击Authorize按钮,跳转到 https://www.baidu.com/?code=tg0GDq,这样我们就拿到了授权码。

  • 通过授权码申请token: 

    @Test
    public void token_code() {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("grant_type", "authorization_code");
        params.add("code", "tg0GDq");
        String response = restTemplate.withBasicAuth("clientId", "clientSecret").postForObject("/oauth/token", params, String.class);
        System.out.println(response);
    }

(3)刷新token

@Test
    public void token_refresh() {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("grant_type", "refresh_token");
        params.add("refresh_token", "fb00358a-44e2-4679-9129-1b96f52d8d5d");
        String response = restTemplate.withBasicAuth("clientId", "clientSecret").
                postForObject("/oauth/token", params, String.class);
        System.out.println(response);
    }

刷新token功能报错,// todo 2018-11-08 此处留坑

二、比较复杂的认证服务器

上面我们搭建的认证服务器存在以下弊端:

  1. clientId和clientSecret是写死在配置文件里的。
  2. 用户信息写死在配置文件里。
  3. 通过clientId和clientSecret获取的code和token都存在内存中。第一:如果服务器宕机code和token会丢失;第二:不支持多点部署。

针对以上问题,我们要做的就是

  1. 将clientId和clientSecret等信息存储在数据库中。
  2. 将用户信息存储在数据库中。
  3. 将code和token存储在redis中。

接下来我们一步一步实现:

1. 创建测试用表及数据

drop table if exists test.oauth2_client;
create table test.oauth2_client (
  id int auto_increment primary key,
  clientId varchar(50),
  clientSecret varchar(50),
  redirectUrl varchar(2000),
  grantType varchar(100),
  scope varchar(100)
);

insert into test.oauth2_client(clientId, clientSecret, redirectUrl, grantType, scope)
values ('clientId','clientSecret','http://www.baidu.com,http://www.csdn.net', 'authorization_code,client_credentials,password,implicit', 'scope1,scope2');


drop table if exists test.oauth2_user;
create table test.oauth2_user (
  id int auto_increment primary key,
  username varchar(50),
  password varchar(50)
);

insert into test.oauth2_user (username, password)
values ('admin','admin');

insert into test.oauth2_user (username, password)
values ('guest','guest');
创建测试用表及数据

相关文章: