Spring Security 实战干货:登录成功后返回 JWT Token

2021-03-29 12:25

阅读:389

标签:一起   根据   login   hash   mamicode   use   服务端   探讨   datetime   

1. 前言

欢迎阅读 Spring Security 实战干货 系列文章,上一文 我们实现了 JWT 工具。本篇我们将一起探讨如何将 JWTSpring Security 结合起来,在认证成功后不再跳转到指定页面而是直接返回 JWT Token 。本文的DEMO 可通过文末的方式获取

2. 流程

JWT 适用于前后端分离。我们在登录成功后不在跳转到首页,将会直接返回 JWT Token 对(DEMO中为JwtTokenPair),登录失败后返回认证失败相关的信息。

3. 实现登录成功/失败返回逻辑

如果你看过 Spring Security 实战干货:玩转自定义登录 将非常容易理解下面的做法。

3.1 AuthenticationSuccessHandler 返回 JWT Token

AuthenticationSuccessHandler 用于处理登录成功后的逻辑,我们编写实现并注入 Spring IoC 容器:

     /**
      * 处理登录成功后返回 JWT Token 对.
      *
      * @param jwtTokenGenerator the jwt token generator
      * @return the authentication success handler
      */
     @Bean
     public AuthenticationSuccessHandler authenticationSuccessHandler(JwtTokenGenerator jwtTokenGenerator) {
         return (request, response, authentication) -> {
             if (response.isCommitted()) {
                 log.debug("Response has already been committed");
                 return;
             }
             Map map = new HashMap(5);
             map.put("time", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
             map.put("flag", "success_login");
             User principal = (User) authentication.getPrincipal();

             String username = principal.getUsername();
             Collection authorities = principal.getAuthorities();
             Set roles = new HashSet();
             if (CollectionUtil.isNotEmpty(authorities)) {
                 for (GrantedAuthority authority : authorities) {
                     String roleName = authority.getAuthority();
                     roles.add(roleName);
                 }
             }

             JwtTokenPair jwtTokenPair = jwtTokenGenerator.jwtTokenPair(username, roles, null);

             map.put("access_token", jwtTokenPair.getAccessToken());
             map.put("refresh_token", jwtTokenPair.getRefreshToken());

             ResponseUtil.responseJsonWriter(response, RestBody.okData(map, "登录成功"));
         };
     }

3.2 AuthenticationFailureHandler 返回认证失败信息

AuthenticationFailureHandler 处理认证失败后的逻辑,前端根据此返回进行跳转处理逻辑,我们也实现它并注入 Spring IoC 容器:

     /**
      * 失败登录处理器 处理登录失败后的逻辑 登录失败返回信息 以此为依据跳转
      *
      * @return the authentication failure handler
      */
     @Bean
     public AuthenticationFailureHandler authenticationFailureHandler() {
         return (request, response, exception) -> {
             if (response.isCommitted()) {
                 log.debug("Response has already been committed");
                 return;
             }
             Map map = new HashMap(2);

             map.put("time", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
             map.put("flag", "failure_login");
             ResponseUtil.responseJsonWriter(response, RestBody.build(HttpStatus.UNAUTHORIZED.value(), map, "认证失败","-9999"));
         };
     }

4. 配置

把上面写好的两个 Handler Bean 写入 登录配置,相关片断如下,详情参见文末 DEMO:

 httpSecurity.formLogin().loginProcessingUrl(LOGIN_PROCESSING_URL).successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler)

5. 验证

我们依然通过 Spring Security 实战干货:玩转自定义登录 一文中章节 6.4 测试 来运行。结果如下:

5.1 登录成功结果

 {
     "httpStatus": 200,
     "data": {
         "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGwiLCJhdWQiOiJGZWxvcmRjbiIsInJvbGVzIjoiW10iLCJpc3MiOiJmZWxvcmQuY24iLCJleHAiOiIyMDE5LTExLTI3IDExOjMxOjMyIiwiaWF0IjoiMjAxOS0xMC0yOCAxMTozMTozMiIsImp0aSI6IjdmYTBlOWFiYjk5OTRjZGRhNGM5NjI4YzExNGM3YTk4In0.PvVsc8w10_0C5UIifJS1S5dEia5PQoVc_6wMfLAZOf574kt-VopHBVEp2zkjC1CNN3ltchy5rx6samaBDQvqWgoeFLXbRgNOa9Qhdf0wMLf-pUqoKRHuhBZV9HsvXSyQCFjZWlIguv4FSPZhbEff6D_8QUXmdWjlF_XEG2BPMr4",
         "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGwiLCJhdWQiOiJGZWxvcmRjbiIsInJvbGVzIjoiW10iLCJpc3MiOiJmZWxvcmQuY24iLCJleHAiOiIyMDIwLTAxLTI2IDExOjMxOjMyIiwiaWF0IjoiMjAxOS0xMC0yOCAxMTozMTozMiIsImp0aSI6IjdmYTBlOWFiYjk5OTRjZGRhNGM5NjI4YzExNGM3YTk4In0.Caj4AAothdUwZAFl8IjcAZmmXHgTt76z8trVG1sf_WHZucFVcHR8FWjShhITpArsQpmokP6GBTMsCvWDl08fUVZBpOWc1CdPUAIIEdArHCFzO64HXc_DLSyg9v0C-qYfxaTlf0npL5QxpBBr9sJcyzxZF3CnpfZpAxm8WZzXG6o",
         "time": "2019-10-28 11:32:11",
         "flag": "success_login"
     },
     "msg": "登录成功",
     "identifier": ""
 }

我们取 access_token 使用官网jwt.io 提供的解码功能进行解码如下:

技术图片

5.2 登录失败结果

 {
     "httpStatus": 401,
     "data": {
         "time": "2019-10-28 12:54:10",
         "flag": "failure_login"
     },
     "msg": "认证失败",
     "identifier": "-9999"
 }

6. 总结

今天我们将 JWTSpring Security 联系了起来,实现了 登录成功后返回 JWT Token 。这仅仅是一个开始,在下一篇我们将介绍 客户端如何使用 JWT Token 、服务端如何验证 JWT Token ,敬请关注。

Spring Security 实战干货:登录成功后返回 JWT Token

标签:一起   根据   login   hash   mamicode   use   服务端   探讨   datetime   

原文地址:https://blog.51cto.com/14901317/2528388


评论


亲,登录后才可以留言!