SpringBoot整合Oauth2实现认证授权
应用场景
OAuth2.0 协议的使用场景主要为:第三方登录和开放接口的调用
第三方登录就是使用微信等第三方的方式来登录一个应用或者网站,比如用微信账号登录gitee。
而开发接口的调用,则比如说微信、美团等平台向外提供一些自己的接口,这些接口会由很多商家调用来进行开发,对于这些接口的调用则同样可以使用 OAuth2.0 协议。
应用搭建
授权服务器
- 引入依赖
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- 增加授权配置
/**
* 模拟第三方授权配置
*/
@EnableAuthorizationServer
@Configuration
public class AuthConfig extends AuthorizationServerConfigurerAdapter {
@Resource
ClientDetailsService clientDetailsService;
/**
* 资源服务器校验Token
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.checkTokenAccess("permitAll()").allowFormAuthenticationForClients();
}
/**
* 第三方客户端请求配置,和资源服务访问的配置,不设置默认都可以访问,提供默认回调地址
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("cc_client")
.secret(new BCryptPasswordEncoder().encode("cc_secret"))
.resourceIds("cc_resource")
.authorizedGrantTypes("authorization_code","refresh_token")
.scopes("all")
.redirectUris("http://localhost:9093/notify.html");
}
/**
* 配置访问端点
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authorizationCodeServices(authorizationCodeServices()).tokenServices(tokenServices());
}
/**
* 内存管理
*/
@Bean
AuthorizationCodeServices authorizationCodeServices() {
return new InMemoryAuthorizationCodeServices();
}
/**
* Token管理规则
*/
@Bean
AuthorizationServerTokenServices tokenServices() {
DefaultTokenServices services = new DefaultTokenServices();
services.setClientDetailsService(clientDetailsService);
services.setSupportRefreshToken(true);
services.setTokenStore(tokenStore());
services.setAccessTokenValiditySeconds(3600);
services.setRefreshTokenValiditySeconds(3600*7);
return services;
}
@Bean
TokenStore tokenStore() {
return new InMemoryTokenStore();
}
}
- 增加授权服务器的登录校验配置
/**
* 模拟本地用户配置
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 密码加密方式
*/
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 内存中虚拟用户和角色
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin")
.password(new BCryptPasswordEncoder().encode("123456"))
.roles("user");
}
/**
* 表单登录
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().formLogin();
}
}
- 设置端口号9091
资源服务器
- 引入pom依赖
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- 增加资源配置类
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
/**
* Token令牌校验
*/
@Bean
RemoteTokenServices tokenServices() {
RemoteTokenServices services = new RemoteTokenServices();
services.setCheckTokenEndpointUrl("http://localhost:9091/oauth/check_token");
services.setClientId("cc_client");
services.setClientSecret("cc_secret");
return services;
}
/**
* 服务资源ID配置
*/
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("cc_resource").tokenServices(tokenServices());
}
/**
* 模拟用户权限规则
*/
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated();
}
}
- 建立资源API
@RestController
@RequestMapping("/user")
public class ResourceController {
@GetMapping("/get_resource")
public String hello() {
return "我是被保护的资源接口";
}
}
- 设置端口号9092
访问测试
- 认证接口
请求认证接口的链接,询问用户是否同意授权
http://localhost:9091/oauth/authorize?client_id=cc_client&response_type=code
- 进入登录页面,输入用户名密码,点击登录以后,进入授权认证页面。浏览器提示我们,你是否允许cc_client访问你的受保护的资源?
- 选择允许之后,点击授权,会跳转到我们提前配置好的重定向地址 http://localhost:9093/user/hello,同时带上授权码 code 的值
- 根据授权码 code 获取 token。拿到了授权码,我们再根据 grant_type、redirect_url 以及 scope 来使用如下链接,申请令牌 access_token(该链接为 post 请求方式)
http://localhost:9091/oauth/token?code=ox2aO6&grant_type=authorization_code&redirect_uri=http://localhost:8093/notify.html&scope=all
{
"access_token": "47Map5HXp7gio0zWYyLDrygEmQ8",
"token_type": "bearer",
"refresh_token": "Jty8PwzwVMO4MafYTPpAQfrKGGY",
"expires_in": 2212,
"scope": "all"
}
- 校验 token 的正确性
采用 链接 http://localhost:9091/oauth/check_token?token=47Map5HXp7gio0zWYyLDrygEmQ8
,进行 token 正确性的检验。
{
"aud": [
"cc_resource"
],
"user_name": "admin",
"scope": [
"all"
],
"active": true,
"exp": 1672120906,
"authorities": [
"ROLE_user"
],
"client_id": "cc_client"
}
- 访问资源服务器。
http://localhost:9092/user/get_resource
总结
- 当我们需要访问第三方服务(gitee),我们需要微信的认证和授权(认证授权服务器)获取到我们在微信端的用户基础信息(资源服务器),第三方服务会帮我们做跳转。
- 用户进行登录认证,第三方服务可以获取到授权码,根据授权码获取到access_token。
- 第三方应用根据access_token可以获取到资源服务器上面的资源。
项目地址
- https://gitee.com/charles_ruan/demo-oauth2