打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
OAuth2.0 最直观配置

OAuth2.0基础认识可以看这里

spring 全家桶已经实现了 OAuth2.0 的全部功能(spring-cloud-starter-security、spring-security-oauth2-autoconfigure),我们只要引用对应库就可以了。

表结构

无论哪种认证方式,总要把数据存储起来(无论是在缓存还是 DB),OAuth2.0 依赖的数据一般是存放在 DB 中的,全部表结构可以参考这里

其中不能省的表就这一个:oauth_client_details(客户端信息配置,当然了表名可以自己随便改)

 

 

其它用户表、角色权限表、token 存储表等等都可以用我们自己的业务表来做,token 可以存放在 redis 中。

数据结构

用户信息

org.springframework.security.core.userdetails.User

private String password;private final String username;privatefinal Set<GrantedAuthority> authorities;private final booleanaccountNonExpired;private final boolean accountNonLocked;private final booleancredentialsNonExpired;private final boolean enabled;

这个类可以自定义,继承 User 就好了,一般都是用项目中的用户类。

权限信息

可以是菜单权限,也可以数据权限,这个完全根据业务来自定义。

比如使用业务系统的角色 + 权限关系表,就可以知道当前用户能操作哪些菜单 / 数据(Set authorities)。

加密方式(针对 password 模式)

认证过程中提交的密码不能是明文,如果不用默认的加密方式,可以自定义(必须与数据库中存储密码的加密方式匹配)。

@Beanpublic PasswordEncoder passwordEncoder(){    returnPasswordEncoderFactories.createDelegatingPasswordEncoder();}

自定义授权服务器配置

@Configuration@AllArgsConstructor@EnableAuthorizationServerpublicclass AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{private final DataSource dataSource;private final UserDetailsServiceuserDetailsService;private final AuthenticationManagerauthenticationManager;    // 用户信息和token存放在redis中privatefinal RedisConnectionFactoryredisConnectionFactory;@Override@SneakyThrowspublic voidconfigure(ClientDetailsServiceConfigurer clients){        // 自定义用户查询实现类MyClientDetailsService clientDetailsService = newMyClientDetailsService(dataSource);       // 自定义查询oauth_client_details数据的sql(根据client_id查询)clientDetailsService.setSelectClientDetailsSql("select* from ...");        // 自定义查询所有oauth_client_details数据的sqlclientDetailsService.setFindClientDetailsSql("select* from...");clients.withClientDetails(clientDetailsService);}@Overridepublicvoid configure(AuthorizationServerSecurityConfigurer oauthServer){oauthServer             //让 /oauth/token 支持 client_id 以及 client_secret 作登录认证.allowFormAuthenticationForClients()            // 允许可访问 /oauth/check_token 对应的api.checkTokenAccess("permitAll()");}@Overridepublicvoid configure(AuthorizationServerEndpointsConfigurer endpoints){endpoints            // oauth请求使用get或put方式.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST)            // token存储方式.tokenStore(tokenStore())            // 自定义token中附加信息的内容.tokenEnhancer(tokenEnhancer())            // 获取用户信息的实现类.userDetailsService(userDetailsService).authenticationManager(authenticationManager)            // 是否重复使用refreshToken直到过期.reuseRefreshTokens(false)            // 自定义授权确认api.pathMapping("/oauth/confirm_access","/token/confirm_access")            // 自定义异常处理类.exceptionTranslator(newMyWebResponseExceptionTranslator());}@Beanpublic TokenStore tokenStore(){RedisTokenStore tokenStore = newRedisTokenStore(redisConnectionFactory);tokenStore.setPrefix("myOAuth2.0");returntokenStore;}@Beanpublic TokenEnhancer tokenEnhancer() {return (accessToken,authentication) -> {final Map<String, Object> additionalInfo = newHashMap<>();additionalInfo.put("addInfo", "额外信息");((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(additionalInfo);return accessToken;};}}

授权服务器正确分配了 token 后,在后续的请求过程中,资源服务器怎么从 token 上获取用户信息呢?这就需要在资源服务器中配置了。

自定义资源服务器配置

public class MyResourceServerConfigurerAdapter extendsResourceServerConfigurerAdapter {    // 自定义异常处理类@AutowiredprotectedResourceAuthExceptionEntryPoint resourceAuthExceptionEntryPoint;   // 验证token是否有效,默认即可,无需自定义@AutowiredprotectedRemoteTokenServices remoteTokenServices;    // 自定义拒绝授权处理器@Autowiredprivate AccessDeniedHandlermyAccessDeniedHandler;    // 允许匿名访问的资源,支持ant通配符@Autowiredprivate List<String>permitUrls;    // rest请求模板,默认即可@AutowiredprivateRestTemplate restTemplate;@Override@SneakyThrowspublic voidconfigure(HttpSecurity httpSecurity){ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistryregistry = httpSecurity.authorizeRequests();        //可匿名访问资源permitUrls.forEach(url ->registry.antMatchers(url).permitAll());       // 所有页面需要授权registry.anyRequest().authenticated().and().csrf().disable();}@Overridepublicvoid configure(ResourceServerSecurityConfigurer resources) {DefaultAccessTokenConverteraccessTokenConverter = newDefaultAccessTokenConverter();        // 关键位置,根据check_token返回的结果,转换为资源服务器中可用的用户信息UserAuthenticationConverteruserTokenConverter = newMyUserAuthenticationConverter();accessTokenConverter.setUserTokenConverter(userTokenConverter);remoteTokenServices.setRestTemplate(restTemplate);remoteTokenServices.setAccessTokenConverter(accessTokenConverter);resources.authenticationEntryPoint(resourceAuthExceptionEntryPoint).accessDeniedHandler(myAccessDeniedHandler).tokenServices(remoteTokenServices);}}

这里的UserAuthenticationConverter 会根据 check_token 返回的内容来生成一个 org.springframework.security.core.userdetails.User 并把它放在org.springframework.security.authentication.UsernamePasswordAuthenticationToken中,这样后面的处理逻辑都能从权限管理器中获取到用户信息了。

那 check_token 是怎么获取的 token 信息呢?

之前我们不是配置了 token 在 redis 中存储么?

@Beanpublic TokenStore tokenStore() {   RedisTokenStore tokenStore = newRedisTokenStore(redisConnectionFactory);   tokenStore.setPrefix("myOAuth2.0");    returntokenStore;}

在 RedisTokenStore 中你会看到是如何反序列化出来的

@Overridepublic OAuth2AuthenticationreadAuthenticationForRefreshToken(OAuth2RefreshToken token) {   return readAuthenticationForRefreshToken(token.getValue());}publicOAuth2Authentication readAuthenticationForRefreshToken(String token) {    RedisConnectionconn = getConnection();    try{        byte[] bytes =conn.get(serializeKey(REFRESH_AUTH +token));        OAuth2Authentication auth =deserializeAuthentication(bytes);       return auth;    } finally{        conn.close();    }}

redis 中存储的内容如下,其实就是一个序列化的 org.springframework.security.oauth2.provider.OAuth2Authentication 对象

到这里,Oauth2.0 的配置就很清楚了吧,后面我们再把整个请求过程串起来,就更直观了!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
使用Spring Cloud Security OAuth2搭建授权服务
Oauth2 JWT登出(黑名单方案)
决定放弃 JWT 了!
理解JWT的使用场景和优劣
可能是第二好的 Spring OAuth 2.0 文章,艿艿端午在家写了 3 天~
微服务架构SpringCloud
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服