SpringBoot整合JWT

本文最后更新于2023.03.28-18:13,某些文章具有时效性,若有错误或已失效,请在下方留言或联系涛哥

介绍

JSON Web Token(JWT)是一种开放标准,用于作为Web应用中的令牌,用于在各方之间安全地将信息作为JSON对象传输。在数据传输中完成数据加密、签名等相关处理。

实现前后端分离就用JWT

Jwt的核心是什么:一种信息交换,一种是用来做javaweb中的安全验证

流程

  1. 用户使用用户名密码请求服务器

  2. 服务器验证用户信息

  3. 服务器通过验证发送给用户一个token

  4. 客户端存储token,并每次请求时附带一个token值

  5. 服务器验证token并返回数据

实现案例

1,在pom.xml里导入依赖配置

      <!-- 导入jwt-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.18.3</version>
        </dependency>

 2,新建一个po文件夹里面存放下面两个Java文件

info.java

package com.xxgc.helloworld.po;
​
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
​
//Lombok自动生成set get方法
@Data
//全参构造
@AllArgsConstructor
//无参构造
@NoArgsConstructor
public class Info {
    //返回状态码
    private Integer code;
    //返回信息
    private String msg;
    //返回的数据
    private Object data;
    //版本号
    private String version;
    //请求响应时间
    private Date ResponseDate;
​
    public Info(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public Info(Integer code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
}

TokenInfo.java

package com.xxgc.helloworld.po;
​
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
​
/**
 * @program: helloworld
 * @description: token返回
 * @author: liutao
 * @create: 2022-03-07 17:25
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TokenInfo {
    /**
     * 返回状态码
     * 401 登录过期 或未登录
     * -202 无效签名
     * -203 算法不一致
     * -204 token无效
     */
    private Integer code;
    //返回信息
    private String message;
}

 3,新建一个config文件夹并新建以下文件

InterceptorConfig.java

package com.xxgc.helloworld.config;
​
import com.xxgc.helloworld.interceptor.JWTInterceptors;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
​
import java.util.ArrayList;
​
/**
 * @program: helloword
 * @description: 拦截器配置
 * @author: liutao
 * @create: 2022-03-07 16:11
 **/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
​
    //配置拦截器规则
    public void addInterceptors(InterceptorRegistry registry){
        //swagger相关
        ArrayList<String> swagger = new ArrayList<>();
        swagger.add("/*.html");
        swagger.add("/swagger-resources/**");
        swagger.add("/webjars/**");
        swagger.add("/v2/**");
        swagger.add("/swagger-ui.html/**");
        //jwt 相关
        registry.addInterceptor(new JWTInterceptors())
                .addPathPatterns("/**")//需要进行token验证的
                .excludePathPatterns("/login/namePassLogin")//放行的
                .excludePathPatterns(swagger);//放行swagger相关
    }
}

 4,新建一个interceptors文件夹

JWTInterceptors.java

package com.xxgc.helloworld.interceptor;
​
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xxgc.helloworld.po.TokenInfo;
import com.xxgc.helloworld.utils.JWTUtils;
import org.springframework.web.servlet.HandlerInterceptor;
​
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @program: helloworld
 * @description: JWT拦截器
 * @author: liutao
 * @create: 2022-03-07 15:55
 **/
public class JWTInterceptors implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        TokenInfo info = new TokenInfo();
        // 获取请求头中令牌
        String token = request.getHeader("token");
        try {
            JWTUtils.verify(token);// 验证令牌
            return true;  // 放行请求
        } catch (SignatureVerificationException e) {
            info.setCode(-202);
            info.setMessage("无效签名");
        }catch (TokenExpiredException e){
            info.setCode(401);
            info.setMessage("登录过期");
        }catch (AlgorithmMismatchException e){
            info.setCode(-203);
            info.setMessage("算法不一致");
        }catch (Exception e){
            info.setCode(-204);
            info.setMessage("token无效");
        }
        // 将map以json的形式响应到前台  map --> json  (jackson)
        String json = new ObjectMapper().writeValueAsString(info);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return false;
    }
}

5,新建utils文件夹

JWTUtils.java

package com.xxgc.helloworld.utils;
​
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
​
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
​
/**
 * @program: helloword
 * @description: JWT工具类
 * @author: liutao
 * @create: 2022-03-07 15:20
 **/
public class JWTUtils {
    /**
     * 加密和解密使用的密钥
     * */
    private static final String SING = "NIUYEYE";
    //用于获取token
    public static String getToken(Map<String,String> map){
        Calendar instance = Calendar.getInstance();
        //配置令牌失效时间 20秒后失效 (项目当中一般30分钟)
        instance.add(Calendar.DATE,1);
        //创建jwt
        JWTCreator.Builder builder = JWT.create();
        map.forEach((k,v) ->{
            builder.withClaim(k,v);
        });
        String token = builder
                .withExpiresAt(instance.getTime())//过期时间
                .sign(Algorithm.HMAC256(SING));//签名
        return token;
    }
    //合法性 校验
    public static DecodedJWT verify(String token){
        return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
    }
}​

6,调用

在用户登录成功以后生成token

package com.xxgc.helloworld.service.Impl;

import com.xxgc.helloworld.bean.Users;
import com.xxgc.helloworld.bean.UsersExample;

import com.xxgc.helloworld.dao.UsersMapper;
import com.xxgc.helloworld.po.Info;
import com.xxgc.helloworld.service.ILoginService;
import com.xxgc.helloworld.utils.JWTUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
@Service
public class LoginService implements ILoginService {
    //业务逻辑层和dao层关联
    @Autowired
    private UsersMapper um;

    //ctrl + q
    @Override
    public Info namePassLogin(Users u) {
        UsersExample example = new UsersExample();
        example.createCriteria()
                .andUsernameEqualTo(u.getUsername())
                .andPasswordEqualTo(u.getPassword());
        //alt+shift+l    ctrl+alt+v  生成返回结果
        List<Users> users = um.selectByExample(example);
        //判断是否为空
        if (CollectionUtils.isEmpty(users)) {
            return new Info(-200, "用户名或密码错误");
        } else {
            HashMap<String, String> map = new HashMap<>();
            map.put("username",users.get(0).getUsername());
            String token= JWTUtils.getToken(map);
            map.put("token",token);
            return new Info(200, "登录成功", map);
        }

    }
}

7,登录返回token

没有token时访问,因为被拦截器拦截不能被放行

当携带token时正常访问

阅读剩余
THE END