专栏首页码农小胖哥的码农生涯Spring Security 实战干货:登录成功后返回 JWT Token

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

1. 前言

欢迎阅读 Spring Security 实战干货 系列文章,上一文 我们实现了 JWT 工具。本篇我们将一起探讨如何将 JWT 与 Spring 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<String, Object> 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<GrantedAuthority> authorities = principal.getAuthorities();
             Set<String> 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<String, Object> 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. 总结

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

本文分享自微信公众号 - 码农小胖哥(Felordcn),作者:码农小胖哥

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 想学会 Spring Boot 你必须深刻了解这些概念

    Spring Boot是一个难以理解的框架。在本文中,我们将了解Spring Boot的基础知识,并帮助您了解重要的概念-starter,自动配置和Parent...

    码农小胖哥
  • Spring 5的最终功能发行版即将来临

    2020 年 6 月 25 日Spring Framework团队发布博客宣布Spring Framework最新的里程碑版本Spring Framework ...

    码农小胖哥
  • Java开发常用技术栈盘点

    最近很多人私下询问我常用的Java开发技术栈,所以今天就总结一波平常使用的Java技术栈。

    码农小胖哥
  • 超全!CIS Controls中英双语对照

    CIS是一个社区驱动的非营利组织,负责管理维护CIS Controls®和CIS benchmark™,全球公认保护IT系统和数据的最佳实践。CIS领导全球IT...

    FB客服
  • java直接读取.zip压缩文件ZipEntry.getsize()总是返回-1?

    但是后面发现一个问题,读取的时候总是返回-1 ze.getSize()的值总是-1,可是名字都到了。 找不到法子,着实无奈,后面换了种方式,干脆将文件解压出来之...

    软测小生
  • 第四节 Go语言数据类型

    干货来了!!!为了让更多的小伙伴喜欢Golang、加入Golang之中来,Golang语言社区发起人彬哥联合业界大牛共同推出了Go语言基础、进阶、提高课程,目前...

    李海彬
  • 人工智能不可能超越人类,原因居然是这样的…

    多样性vs.奇点 Goldberg说,大部分恐惧主要源于奇点,届时AI和机器人将超越人类智能。与其担心遥不可及的奇点,他建议我们多关注多样性,即人与机器人协作...

    机器人网
  • 2015 MVP OpenDay 及 Community Camp 演讲PPT分享

    这两天来到首都北京参加一年一度的MVP OpenDay 和 MVP Community Camp。其中,31号下午有我的课程:What Will You Mak...

    ShiJiong
  • 1--debug时安卓源码不一致问题--Source code does not match the bytecode

    张风捷特烈
  • spring mvc报错,数据库查询无限死循环

    进行查询的陷入了无限死循环,原因是问题类中包含了回答,回答类中包含了问题,进入了无限死循环 解决方法:在回答类中的问题类属性上加注解:@JsonBackRefe...

    二十三年蝉

扫码关注云+社区

领取腾讯云代金券