一、最简单认证服务器
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默认的登录页面:
-
输入用户名/密码:admin/admin,点击登录后跳转到确认授权页面:
-
至少选中一个,然后点击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 此处留坑
二、比较复杂的认证服务器
上面我们搭建的认证服务器存在以下弊端:
- clientId和clientSecret是写死在配置文件里的。
- 用户信息写死在配置文件里。
- 通过clientId和clientSecret获取的code和token都存在内存中。第一:如果服务器宕机code和token会丢失;第二:不支持多点部署。
针对以上问题,我们要做的就是
- 将clientId和clientSecret等信息存储在数据库中。
- 将用户信息存储在数据库中。
- 将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');