JWT登录认证Springboot详解

 更新时间:2024年11月20日 15:04:08   作者:十&年  
文章主要介绍了如何在Java项目中使用JWT进行用户认证和授权,通过定义一个常量,编写JWT工具类来生成和解析token,登录时在服务端生成token并返回给客户端,客户端使用拦截器拦截请求,验证token的有效性,从而实现权限控制,文章旨在分享个人经验,为开发者提供参考

SystemPara.SECRET 是自己定义的常量

依赖

        <!-- token -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.3.0</version>
        </dependency>

一、JWT工具类

package com.cn.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.cn.util.SystemPara;
import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm;

import java.io.UnsupportedEncodingException;
import java.security.SignatureException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
  * @Author 徐本锡
  * @Date 2019/7/4
  * @Param
  * @return
  **/
public class JWTUtil {

    private static final long EXPIRE_TIME = 5 * 60 * 1000;

    public static final String TOKEN_HEADER = "token";
    public static final String TOKEN_PREFIX = "xbx_";

    /**
      * @Author 徐本锡
      * @Description 生成token
      * @Date 2019/7/4  
      * @Param 
      * @return 
      **/
    public static  String  createToken (String logon_name) throws UnsupportedEncodingException {

        //签名发布时间
        Date createTime = new Date();

        //设置签名过期时间  5分钟
        Calendar nowTime=Calendar.getInstance();
        nowTime.add(Calendar.MINUTE,5);
        Date expiresTime = nowTime.getTime();
        //Date expiresTime = new Date(System.currentTimeMillis() + EXPIRE_TIME);

        Map<String,Object> map=new HashMap<String, Object>();
        map.put("alg","HS256");//设置算法 为HS256
        map.put("typ","JWT");//设置类型为JWT

        String token= JWT.create()
                .withHeader(map)
                .withClaim("logon_name",logon_name) //可以将基本不重要的对象信息放到claims中
                .withIssuedAt(createTime)//设置签发时间
                .withExpiresAt(expiresTime)//设置过去时间 过期时间大于签发时间
                .sign(Algorithm.HMAC256(SystemPara.SECRET));//用公共密钥加密

        return token;

    }

    /**
     * 校验token是否正确
     *
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String logon_name, String secret) {
        try {
            //根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(SystemPara.SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("logon_name", logon_name)
                    .build();
            //效验TOKEN
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getLogonName(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("logon_name").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

}

二、登录时生成token

service方法中生成token,然后放入返回结果

  //service方法中生成token,然后放入返回结果
  String token = JWTUtil.createToken(loginName);
  resultMap.put("token", token);

controller中 把token放入 response响应中

package com.cn.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cn.domain.EmpinforVo;
import com.cn.service.LogonService;
import com.cn.util.JWTUtil;
import com.cn.util.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author xbx
 * @date 2019-05-13
 */
@RestController
@RequestMapping("/Logon")
public class LogonController {
    private final LogonService logonService;

    @Autowired
    public LogonController(LogonService logonService) {
        this.logonService = logonService;
    }

    @RequestMapping(value = "", method = RequestMethod.POST)
    public R logon(HttpServletResponse response, EmpinforVo entity) throws Exception{
        Map resultMap = logonService.logon(entity);
        String token = (String) resultMap.get("token");

        //放到响应头部
        response.setHeader(JWTUtil.TOKEN_HEADER, JWTUtil.TOKEN_PREFIX + token);

        return R.success(resultMap);
    }

}

三、创建拦截器

package com.cn.interceptor;

import com.cn.util.JWTUtil;
import com.cn.util.SystemPara;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * token验证拦截
 */
public class JwtInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        // 取得token
        String tokenHeader = request.getHeader(JWTUtil.TOKEN_HEADER);
        if (tokenHeader == null || "".equals(tokenHeader)) {
            throw new Exception("token不存在");
        }
        if (!tokenHeader.startsWith(JWTUtil.TOKEN_PREFIX)) {
            throw new Exception("这是你自己造的token吧");
        }
        String token = tokenHeader.replace(JWTUtil.TOKEN_PREFIX, "");//真正的token

        String logonName = JWTUtil.getLogonName(token);

        // 验证token是否有效
        if (!JWTUtil.verify(token, logonName, SystemPara.SECRET)){
            throw new Exception("token已失效");
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub

    }

}

四、配置拦截器

package com.cn.config;

import com.cn.interceptor.JwtInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


/**
  * @Author 徐本锡
  **/
@Configuration
public class WebAppConfiguration implements WebMvcConfigurer  {

    /**
     * 配置静态资源
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String path= "/";
        for(int i=1900; i<=2500; i++){
            path = String.valueOf(i);
            registry.addResourceHandler("/"+path+"/**").addResourceLocations("file:C:/"+path+"/");
            registry.addResourceHandler("/"+path+"/**").addResourceLocations("file:/"+path+"/");
        }
    }

    /**
     * 跨域支持
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH")
                .maxAge(3600 * 24);
    }

    /**
     * 添加拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //拦截路径可自行配置多个 可用 ,分隔开
        registry.addInterceptor(new JwtInterceptor()).addPathPatterns("/**").excludePathPatterns("/Logon");
    }


}   

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java设计模式之装饰器模式

    Java设计模式之装饰器模式

    这篇文章介绍了Java设计模式之装饰器模式,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-09-09
  • SpringBoot+Mybatis-plus实现分页查询的示例代码

    SpringBoot+Mybatis-plus实现分页查询的示例代码

    本文主要介绍了SpringBoot+Mybatis-plus实现分页查询的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-02-02
  • 解决Tomcat修改get提交请求乱码问题

    解决Tomcat修改get提交请求乱码问题

    这篇文章主要介绍了Tomcat修改get提交请求乱码问题的解决方案,需要的朋友参考下
    2017-04-04
  • Java实现Excel表单控件的添加与删除

    Java实现Excel表单控件的添加与删除

    本文通过Java代码示例介绍如何在Excel表格中添加表单控件,包括文本框、单选按钮、复选框、组合框、微调按钮等,以及如何删除Excel中的指定表单控件,需要的可以参考一下
    2022-05-05
  • Java后台与微信小程序的数据交互实现

    Java后台与微信小程序的数据交互实现

    这篇文章主要介绍了Java后台与微信小程序的数据交互实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • SpringMVC中Controller层获取前端请求参数的方式汇总

    SpringMVC中Controller层获取前端请求参数的方式汇总

    这篇文章主要介绍了SpringMVC中Controller层获取前端请求参数的几种方式,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • java中json和对象之间相互转换的运用

    java中json和对象之间相互转换的运用

    本文主要介绍了java中json和对象之间相互转换的运用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • SpringBoot中读取application.properties配置文件的方法

    SpringBoot中读取application.properties配置文件的方法

    这篇文章主要介绍了SpringBoot中读取application.properties配置文件的三种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-02-02
  • Spring用AspectJ开发AOP(基于Annotation)

    Spring用AspectJ开发AOP(基于Annotation)

    这篇文章主要介绍了Spring用AspectJ开发AOP(基于Annotation),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • Java基础知识精通块作用域与条件及switch语句

    Java基础知识精通块作用域与条件及switch语句

    块(block,即复合语句)是指由若干条 Java 语句组成的语句,并由一对大括号括起来。块确定了变量的作用域。一个块可以嵌套在另一个块中;条件语句、switch语句是我们常见会用到的结构,感兴趣的朋友来看看吧
    2022-04-04

最新评论