zoukankan      html  css  js  c++  java
  • Spring Security OAuth 2.x的刷新token接口/oauth/token自定义修改

    参考资料:

    在OAuth 2中模仿DefaultTokenServices写一个新的tokenServices来提供个性化服务
    https://my.oschina.net/u/3768341/blog/2998273

    Spring Security OAuth 2.x的刷新token方法自定义修改

    使用maven依赖:

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

    需求:

    旧项目的其中一个前端页面会频繁调用token刷新方法。

    刷新的token接口会返回一个新的token令牌值给前端,旧的token令牌作废掉。

    刷新接口时Oauth2框架自带的接口

    /oauth/token?access_token=8192be8f-4564-42cc-9f0f-7049be5ee085&grant_type=refresh_token&refresh_token=4f9ad8f9-885c-4cab-9f39-dc18887b526a&scope=read

    请求参数:

    access_token: af917135-211e-4dc4-8403-e436a414f7da
    grant_type: refresh_token
    refresh_token: 4c6f36e8-fb51-44d5-8f87-1ce7e55aa504
    scope: read

    返回数据:

    access_token: "fcb856b1-c325-46cd-bad4-f5d423688a5d"
    expires_in: 1799
    refresh_token: "4c6f36e8-fb51-44d5-8f87-1ce7e55aa504"
    scope: "read"
    token_type: "bearer"

    而前端页面可以打开新的窗口,这个新窗口也需要用到token访问后端。

    到这个新窗口也触发到某一个前端页面的刷新token机制时,会调用token刷新接口。

    导致 新窗口的token值变更的,而旧窗口的token值没有变

    旧窗口再次携带旧token请求后端时因为token无效,重定向跳转到的登录页面。

    解决方法:
    方法1、调用刷新token方法时,不进行token更新,返回原来的token内容。
    可以避免两个窗口的token不一样导致跳转到登录页面。

    本地调式代码后,发现刷新token的最终方法是调用 DefaultTokenServices类的刷新token方法

    OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)

    网上搜索资料,可以在配置时,自定义的tokenService代替默认实现类。

     具体配置类,主要查看第8行,配置endpoints

     1 @Configuration
     2 @EnableAuthorizationServer
     3 public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
     4 
     5     @Override
     6     public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
     7         // 自定义tokenservice方法
     8         endpoints.tokenServices(tokenServices(endpoints));
     9         endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
    10 //                .reuseRefreshTokens(false)
    11                 .authenticationManager(authenticationManager).userDetailsService(defaultUsersDetailsService);
    12     }
    13         
    14     private MyTokenService tokenServices(AuthorizationServerEndpointsConfigurer endpoints) {
    15         MyTokenService tokenServices = new MyTokenService();
    16         tokenServices.setTokenStore(tokenStore);
    17         tokenServices.setSupportRefreshToken(true);//支持刷新token
    18         tokenServices.setReuseRefreshToken(true);
    19         tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
    20         tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
    21         addUserDetailsService(tokenServices, defaultUsersDetailsService);
    22         return tokenServices;
    23     }
    24 
    25     private void addUserDetailsService(MyTokenService tokenServices, UserDetailsService userDetailsService) {
    26         if (userDetailsService != null) {
    27             PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
    28             provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(
    29                     userDetailsService));
    30             tokenServices.setAuthenticationManager(new ProviderManager(Arrays.asList(provider)));
    31         }
    32     }

    自定义的类MyTokenService是复制 DefaultTokenService代码

    修改了刷新token的方法

    MyTokenService.java

     1 public class MyTokenService implements AuthorizationServerTokenServices, ResourceServerTokenServices,
     2         ConsumerTokenServices, InitializingBean {
     3     /**
     4      * 修改刷新token方法,只更新token时间,不更换旧的token值
     5      * @param refreshTokenValue
     6      * @param tokenRequest
     7      * @return
     8      * @throws AuthenticationException
     9      */
    10     @Override
    11     @Transactional(noRollbackFor={InvalidTokenException.class, InvalidGrantException.class})
    12     public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
    13             throws AuthenticationException {
    14 
    15         。。。前面没动
    16 
    17         OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
    18         // 保留token原值
    19         ((DefaultOAuth2AccessToken)accessToken).setValue(tokenRequest.getRequestParameters().get("access_token"));
    20         tokenStore.storeAccessToken(accessToken, authentication);
    21         if (!reuseRefreshToken) {
    22             tokenStore.storeRefreshToken(refreshToken, authentication);
    23         }
    24         return accessToken;
    25     }

    重新启动项目,刷新token接口调用后,返回的还是原来的token值

    作者:海绵般汲取
    出处:https://www.cnblogs.com/gne-hwz/
    版权:本文版权归作者和博客园共有
    转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
  • 相关阅读:
    Linux系统性能优化
    Linux内核模块
    Linux守护进程的启动方法
    已有的游戏如何快速稳定迁移到云上?
    项目重构--使用策略模式
    设计模式学习--装饰者模式(Decorator Pattern)
    C#/ASP.NET应用程序配置文件app.config/web.config的增、删、改操作
    Resharper上手指南
    ReSharper 配置及用法(转)
    使用线程新建WPF窗体(公用进度条窗体)
  • 原文地址:https://www.cnblogs.com/gne-hwz/p/15273397.html
Copyright © 2011-2022 走看看