springboot进阶学习(十六)springboot集成jwt

springboot集成jwt

jwt简介

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519),jwt里面包含了一些用户信息,服务器不用再存储或者查询用户信息,减轻服务器压力。

传统Cookie+Session与jwt对比

  • 传统Cookie+Session:用户登录成功,服务器会给客户端一个sessionId,客户端每次请求都要带上这个sessionId,服务器端要存储所有sessionId的信息。
  • jwt:用户登录成功,服务器会给客户端返回一个token(一个字符串),客户端每次请求都要带上这个token,服务器端不用存储任何信息,token里面包含用户的信息。

jwt的组成

  • header:第一部分为头部
  • payload:第二部分我们称其为载荷
  • signature:第三部分是签证
    三个部分中间用.连接起来,一个标准的jwt生成的token格式如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbk5hbWUiOiJhZG1pbiIsImV4cCI6MTU5Mzc3NTc1Nn0._uNz4wJ27IKpqwPYd9RsCNpDKCWCz8rjXI8hH6Ea2J4

jwt优缺点

优点:
  • 不用在服务器端保存session信息,jwt生成的token会携带用户的基本信息
  • 基于标准化:接口可以采用标准化的 JSON Web Token (JWT)
缺点:
  • 无法废弃:登录成功后JWT会给一个token,在到期之前这个token会始终有效,无法中途废弃。
  • 无法续签:如果我们设置jwt的token时长是30分钟,30分钟到了之后,用户还得重新登录,重新获得一个token。传统的Cookie续签方案一般都是用户在使用的时候会自动更新有效时间,保证用户在使用的时候不用重新登录。

应用场景

一次性验证:有些网站在我们注册后会给邮箱发送一个链接,让我们在30分钟内认证,如果我们在30分钟内点了这个链接,就可以认证成功,如果30分钟内没有点,这个链接就失效了。

示例

  • 引入jwt依赖
<!--jwt-->
<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
  <version>3.10.3</version>
</dependency>
  • 创建jwt工具类JwtUtil
public class JwtUtil {
    /**
     * 过期时间为30分钟
     */
    private static final long EXPIRE_TIME = 30*60*1000;

    /**
     * token私钥
     */
    private static final String TOKEN_SECRET = "www.moyundong.com";

    /**
     * 生成签名,15分钟后过期
     * @param sysUser
     * @return
     */
    public static String sign(SysUser sysUser){
        //过期时间
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        //私钥及加密算法
        Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
        //设置头信息
        Map<String, Object> header = new HashMap<>();
        header.put("typ", "JWT");
        header.put("alg", "HS256");
        //附带username和userID生成签名
        return JWT.create().withHeader(header).withClaim("loginName",sysUser.getUsername())
                .withClaim("userId",sysUser.getId()).withExpiresAt(date).sign(algorithm);
    }

    /**
     * 验证token
     * @param token
     * @return
     */
    public static boolean verity(String token){
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        } catch (JWTVerificationException e) {
            return false;
        }
    }
}

在JwtUtil里面,我们有两个方法,sign是用来生成签名的,最终会给我们返回一个token。verity方法使用来验证token是否合法的,如果token错误或者失效的时候就会返回false

  • 创建实体类SysUser
@Data
public class SysUser {
    private String id;
    private String username;
    private String password;
}
  • 创建自定义拦截器
@Component
public class MyInterceptor implements HandlerInterceptor {
    //这个方法是在访问控制器(controller)之前执行的
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("*********1、这个方法在控制器之前执行******************");

        String token = request.getHeader("token");
        if(StringUtils.isEmpty(token)){
            throw new SignatureException("token不能为空");
        }

        boolean verity = JwtUtil.verity(token);
        //如果验证失败就返回错误信息
        if (!verity){
            throw new SignatureException("token失效,请重新登录");
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("*********3、这个方法在控制器之后执行******************");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("*********4、这个方法最后执行******************");
    }
}

在拦截器里面,我们获取请求的token信息,并且通过JwtUtil的verity方法验证信息是否合法,如果不合法就抛出一个异常,如果合法就返回true

  • 创建拦截器配置类
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Autowired
    private MyInterceptor myInterceptor;

    // 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //addInterceptor 注册拦截器
        //addPathPatterns 表示拦截的控制器
        //excludePathPatterns表示排除的控制器
        registry.addInterceptor(myInterceptor).addPathPatterns("/sysUser/*").excludePathPatterns("/sysUser/login");
    }
}
  • 创建测试类
@RestController
@RequestMapping("sysUser")
public class SysUserController {

    /**
     *
     * @return
     */
    @RequestMapping("listAll")
    public Object listAll(){
        SysUser sysUser = new SysUser();
        sysUser.setPassword("123456");
        sysUser.setUsername("niumowang");
        return sysUser;
    }

    @RequestMapping("login")
    public Object login(SysUser sysUser){
        Map<String, Object> result = new HashMap<>();
        //身份验证,这里为了举例,用户名和密码写死,不查数据库了
        if ("admin".equals(sysUser.getUsername()) && "123456".equals(sysUser.getPassword())){
            // 登录成功后进行jwt的签名,并且返回token
            String token = JwtUtil.sign(sysUser);
            result.put("msg","登录成功");
            result.put("token",token);
        }else{
            result.put("msg","登录失败");
        }
        return result;
    }
}

测试类里面只有一个登录和查询的方法,只是为了测试效果用,所以用户名和密码没有查询数据库

  • 创建启动类
@SpringBootApplication
public class Springboot2Test16Application extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(Springboot2Test16Application.class, args);
    }
}
  • 创建application.yml
server:
  port: 8088 # 配置端口
  servlet:
      context-path: /moyundong # 配置项目名称

测试

启动项目后

  • 不登陆,直接在测试工具postman里面输入http://localhost:8088/moyundong/sysUser/listAll,会抛出异常:token不能为空
  • 输入http://localhost:8088/moyundong/sysUser/login?username=admin&password=111111,会提示:登录失败
  • 输入http://localhost:8088/moyundong/sysUser/login?username=admin&password=123456,会提示:登录成功,并且返回一个token
    例如:{"msg":"登录成功","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbk5hbWUiOiJhZG1pbiIsImV4cCI6MTU5Mzc3NTc1Nn0._uNz4wJ27IKpqwPYd9RsCNpDKCWCz8rjXI8hH6Ea2J4"}
  • 登录成功后,在测试工具postman里面输入http://localhost:8088/moyundong/sysUser/listAll并且在headers里面加上token,token的值为登录返回的值,这样会查询出信息

本节示例下载地址:java相关demo下载列表

1介绍
2springboot定时任务
3springboot定时任务配置详解
4springboot动态定时任务
5springboot集成websocket
6springboot多数据源
7springboot配置druid监听
8springboot自定义注解
9springboot常见注解详解
10springboot接收参数详解
11springboot验证机制@Valid和@Validated
12springboot集成Swagger2
13springboot集成swagger-bootstrap-ui
14springboot集成shiro
15springboot集成shiro(二)
16springboot集成jwt
17springboot集成ActiveMQ
18springboot缓存机制

🍉🍉🍉 欢迎大家来博客了解更多内容:java乐园 🍉🍉🍉

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值