tnblog
首页
视频
资源
登录

Spring boot 简单实现jwt

7314人阅读 2020/4/2 9:55 总访问:51089 评论:1 收藏:0 手机
分类: Java


JWT 的原理


基于Token的身份验证用来替代传统的cookie+session身份验证方法中的session。

token应用流程为:


1、初次登录:用户初次登录,输入用户名密码。


2、密码验证:服务器从数据库取出用户名和密码进行验证。


3、生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT。


4、返还JWT:服务器的HTTP RESPONSE中将JWT返还。


5、带JWT的请求:以后客户端发起请求,HTTP REQUEST HEADER中的Authorization字段都要有值,为JWT,用来验证用户身份以及对路由,服务和资源的访问权限进行验证。请求验证的url可以例如:http://127.0.0.1:8083/change/goodsMenu? token=JWT


JWT 是jsonWebToken 简称,现在流行的前后端分离开发(jwt不止是运用于web应用,app,小程序,H5混合开发都可)基本上都使用jwt来验证用户token,减少了服务器session 的使用,也能减轻服务器的压力,是当下Java开发不二选择

更多的关于jwt的东西都可自行百度,这里就不多赘述


使用JWT

1、添加依赖

  1.          <dependency>
  2.             <groupId>com.auth0</groupId>
  3.             <artifactId>java-jwt</artifactId>
  4.             <version>3.2.0</version>
  5.         </dependency>
  6.         <dependency>
  7.             <groupId>io.jsonwebtoken</groupId>
  8.             <artifactId>jjwt</artifactId>
  9.             <version>0.9.1</version>
  10.         </dependency>

2、找到一个合适的Jwt加密工具

网上的加密工具都不一样,但达到的目的都是一样的

  1. @Component
  2. public class JwtTokenUtil {
  3.     private static final long serialVersionUID = -3301605591108950415L;
  4.     private String secret = ParamUtil.getValue("jwt_secret");
  5.     private Long expiration = Long.valueOf(ParamUtil.getValue("jwt_expiration"));
  6.     private String tokenHeader = ParamUtil.getValue("jwt_tokenHeader");
  7.     private Clock clock = DefaultClock.INSTANCE;
  8.     public String generateToken(UserInfo userInfo) {
  9.         Map<String, Object> claims = new HashMap<>();
  10.         return doGenerateToken(claims, userInfo.getName());
  11.     }
  12.     public String generateToken(UserInfo user, String userName) {
  13.         Map<String, Object> claims = new HashMap<>();
  14.         // 自定义参数,把需要存入token的参数都可以自定义到这里,比如 角色 部门类的关键参数
  15.         claims.put("userId", user.getId());
  16.         claims.put("phone", user.getName());
  17.         return doGenerateToken(claims, userName);
  18.     }
  19.     private String doGenerateToken(Map<String, Object> claims, String subject) {
  20.         final Date createdDate = clock.now();
  21.         final Date expirationDate = calculateExpirationDate(createdDate);
  22.         return Jwts.builder()
  23.                 .setClaims(claims) // 存入自定义参数
  24.                 .setSubject(subject)
  25.                 .setIssuedAt(createdDate)
  26.                 .setExpiration(expirationDate)
  27.                 .signWith(SignatureAlgorithm.HS512, secret)
  28.                 .compact();
  29.     }
  30.     private Date calculateExpirationDate(Date createdDate) {
  31.         return new Date(createdDate.getTime() + expiration);
  32.     }
  33.     public String getUsernameFromToken(String token) {
  34.         return getClaimFromToken(token, Claims::getSubject);
  35.     }
  36.     public <T> getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
  37.         final Claims claims = getAllClaimsFromToken(token);
  38.         return claimsResolver.apply(claims);
  39.     }
  40.     public Claims getAllClaimsFromToken(String token) {
  41.         return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
  42.     }
  43.     private Boolean isTokenExpired(String token) {
  44.         final Date expiration = getExpirationDateFromToken(token);
  45.         return expiration.before(clock.now());
  46.     }
  47.     public Date getExpirationDateFromToken(String token) {
  48.         return getClaimFromToken(token, Claims::getExpiration);
  49.     }
  50. }

3、生产加密token,登录时返回

加密字符串可以得到了,接下来就是运用起来,在登录接口利用jwtTokenUtil 生成一个Token 并在登录接口一并返回

4、拦截器拦截并验证token

  1. @Component
  2. public class LoginInterceptor implements HandlerInterceptor {
  3.     @Autowired
  4.     private JwtTokenUtil jwtTokenUtil;
  5.     @Override
  6.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  7.         // 如果不是映射到方法直接通过
  8.         if (!(handler instanceof HandlerMethod)) {
  9.             return true;
  10.         }
  11.         HandlerMethod handlerMethod = (HandlerMethod) handler;
  12.         Method method = handlerMethod.getMethod();
  13.         String servletPath = request.getServletPath();
  14.         if (methodAnnotation != null) {
  15.             // 判断是否存在令牌信息,如果存在,则允许登录
  16.             //token_access 这就是前端放在请求头中的jwtToken
  17.             String accessToken = request.getHeader("token_access");
  18.             if (ToolUtil.isEmpty(accessToken)) {
  19.                 //这里抛给前端的为一个自定义异常枚举,可自己定义
  20.                //RRException 为继承 RuntimeException 的自定义枚举
  21.                 throw new RRException(RongRunErrorCodeEnum.SYSTEM_LOGIN);
  22.             }
  23.             try {
  24.                 
  25.                 Claims claims = jwtTokenUtil.getAllClaimsFromToken(accessToken);
  26.                 //通过jwt加密工具中自定义参数取出自己想要验证的值,来进行操作
  27.                 Long userId = Long.valueOf(claims.get("userId").toString());
  28.                 //这个可要可不要,通过这里自己在请求中加参数,可以让前端少传几个已经在token中自定义好的值
  29.                 request.setAttribute("userId", userId);
  30.                 //接下来可处理需要验证并且已经通过后的业务
  31.                 
  32.             } catch (ExpiredJwtException e) {
  33.                 response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"token已过期");
  34.                 ServletOutputStream out = response.getOutputStream();
  35.                 OutputStreamWriter ow = new OutputStreamWriter(out, "utf-8");
  36.                 ow.write(JSONObject.toJSONString(ApiJson.returnNG("请登录!")));
  37.                 ow.flush();
  38.                 ow.close();
  39.                 return false;
  40.             } catch (MalformedJwtException e) {
  41.                 response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"token有误");
  42.                 ServletOutputStream out = response.getOutputStream();
  43.                 OutputStreamWriter ow = new OutputStreamWriter(out, "utf-8");
  44.                 ow.write(JSONObject.toJSONString(ApiJson.returnNG("请登录!")));
  45.                 ow.flush();
  46.                 ow.close();
  47.                 return false;
  48.             }
  49.             return true;
  50.     }
  51. }

处理类已经完成,接下来是添加拦截器 自定义类并且实现WebMvcConfigurer

  1. @Configuration
  2. @Slf4j
  3. public class MyInterceptor implements WebMvcConfigurer {
  4. /*
  5.     @Autowired
  6.     private LoginInterceptor loginInterceptor;*/
  7.     /**
  8.      * 重写添加拦截器方法并添加配置拦截器
  9.      */
  10.     @Override
  11.     public void addInterceptors(InterceptorRegistry registry) {
  12.         registry.addInterceptor(loginInterceptor());//添加拦截规则
  13.     }
  14.     @Bean
  15.     public LoginInterceptor loginInterceptor (){
  16.         return new LoginInterceptor();
  17.     }
  18. }

到此就可以完成spring boot 对jwt的实现,也可以实现用户单点登录,这里就不细说。原理就是在用户登录时就在服务器中存入token,在拦截器中获取到并对比即可

* 另外说明,以上时全局拦截,如果有的同志只需要进行局部拦截的话,可以使用自定义注解的方式

Spring boot 中使用注解也时非常方便 如果有同志对注解不是很了解的话,可以百度一哈

1、创建注解类


2、使用注解


3、在拦截规则中使用注解

  1.        Method method = handlerMethod.getMethod();
  2.        // 通过获取注解的方法,判断有注解的方法则需要拦截验证
  3.        YourAnnotation yourAnnotation = method.getAnnotation(YourAnnotation.class);
  4.        // 有 @methodAnnotation 注解,需要认证
  5.        if (yourAnnotation != null) {
  6.            // 判断是否存在令牌信息,如果存在,则允许登录
  7.            String accessToken = request.getHeader("token_access");
  8.            if (ToolUtil.isEmpty(accessToken)) {
  9.                throw new RRException(RongRunErrorCodeEnum.SYSTEM_LOGIN);
  10.            }
  11.            try {
  12.                Claims claims = jwtTokenUtil.getAllClaimsFromToken(accessToken);
  13.               
  14.            } catch (ExpiredJwtException e) {
  15.           }
  16.           }

这样就可以只验证加了自定义注解的接口,实现局部拦截

评价

剑轩

2020/4/2 17:32:20

转java了哇..

在idea下搭建Spring boot+Spring MVC+thymeleaf

今天大兄弟来讲一下在idea下,使用Spring Boot ,搭建Spring MVC+thymeleaf。在Java开发领域,Spring Boot算得上是一颗耀眼...

mybatis在Spring boot的配置

一、去Maven官方找mybatis相关依赖,MyBatis Spring Boot Starter依赖(版本自己定义)&lt;!-- mybatis是映射ORM--&gt; &lt...

Swagger 在Spring boot 的配置

一.创建一个项目,可以直接只添加web 的项目;二.添加swagger的swagger ui 和swagger2:如下1、 在Maven网站搜索springfo...

对于Spring boot项目没发现报错,但无法启动的处理

只需要把main函数里面的类容try catch一般就可以发现问题了

Spring boot +swagger+token

文章借鉴于://https://www.jianshu.com/p/6e5ee9dd5a61一、pom的相关依赖&lt;!--版本控制2.5.5--&gt; &lt;parent&gt; &l...

Spring boot +swagger+mssql +lombok+mybatis的ListDto 参数

一、参数为list实体model时(注意list参数一定要用对应的类型接收传回的参数,不然会报错)接口效果注意list参数默认是必填,...

Mydatis注解增删改查+Spring boot

注意本文有更改:在配置文件里只需配数据库即可pom.xml 里面的配置版本看情况,我是直接在io官网下的,这样可以避免很多版...

Spring boot配置文件的应用

springboot实例注意参数引用是用$

Spring boot 自定义测试类

第一种方式启动类字节码第二中方式

Spring boot 自动配置Condition 1(控制@Bean的创建)

条件导入jedis后才创建该bean,如果没导入就不创建该bean1导依赖2创建Condition参数类3创建bean4测试当没有导入bean时,报的错

Spring boot 自动配置Condition 2(自定义注解控制@Bean的创建)升级版

1、创建condition的参数类2、自定义注解3、替换判断的注解小结案例根据配置文件的设置来判断是否添加该bean配置文件系统自...

Spring boot 自动配置之切换内置服务web

1、修改pom.xml的配置就是把tomcat服务器换成其他服务器,总共有四种服务器2、直接启动

Spring boot 获得第三方bean的方法之@ComponentScan

一、创建一个主工程二、创建其他springboot的工程(model)三、在主工程方法上加@ComponentScan然后就能获取了

Spring boot @Import注解

一、通过导入Bean的形式1、创建其他springboot的工程(model\第三方库)2、创建一个主工程并添加@Import注解二、通过导入配...

Spring boot 获得第三方bean的方发之自定义@Enable

一、创建一个主工程二、创建其他springboot的工程(model)1、创建配置类2、创建自定义注解@EnabUser,此处用到了@Import注...
老子许灵灵,写字第一名
排名
45
文章
7
粉丝
3
评论
2
基于open office 把各种类型转为pdf在线预览
剑轩 : 都是些高大上的问题!
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术