Java生成Token并添加拦截器校验Token,实现判断用户是否登录

添加JWT依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
</dependency>

添加工具类,包含

  • 生成Token方法
  • 从token中获取userId
  • 从token中获取userName
  • 查看Token是否过期
package com.szx.exam.util;

import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;
import java.util.Date;

/**
 * @author songzx
 * @create 2023-06-25 13:55
 */
public class JwtHelper {
    // 随机字符串混淆Token
    private static final String tokenSignKey = "uNvs^pML-E";

    /**
     * 生成Token,并保存userID和userName信息
     * @param userId
     * @param userName
     * @return
     */
    public static String createToken(Long userId, String userName) {
        long tokenExpiration = 1000L * 60 * 60 * 24 * 30; // 过期时间,设置30天
        String token = Jwts.builder()
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                .claim("userId", userId)
                .claim("userName", userName)
                .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                .compressWith(CompressionCodecs.GZIP)
                .compact();
        return token;
    }

    /**
     * 从token中获取userID
     * @param token
     * @return
     */
    public static Long getUserId(String token) {
        if (StringUtils.isEmpty(token)) return null;
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        Integer userId = (Integer) claims.get("userId");
        return userId.longValue();
    }

    /**
     * 从token中获取用户姓名
     * @param token
     * @return
     */
    public static String getUserName(String token) {
        if (StringUtils.isEmpty(token)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        return (String) claims.get("userName");
    }

    /**
     * 查看Token是否过期
     * @param token
     * @return false 未过期,true 已过期
     */
    public static Boolean tokenExpired(String token) {
        try {
            Claims claims = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
            Date expiration = claims.getExpiration();
            Date currentDate = new Date();
            return expiration.before(currentDate);
        } catch (ExpiredJwtException ex) {
            return true;
        } catch (Exception ex) {
            return true;
        }
    }
}

添加 handle

package com.szx.exam.handle;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.szx.exam.exception.SsyxException;
import com.szx.exam.util.JwtHelper;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

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

/**
 * @author songzx
 * @create 2022-10-12 9:48
 */
public class TokenHandle implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(!(handler instanceof HandlerMethod)){
            return true;
        }
        // 从请求头中获取token
        String token = request.getHeader("X-Token");
        // 校验token
        if(StringUtils.isEmpty(token) || JwtHelper.tokenExpired(token)){
            throw new SsyxException("登录过期,请重新登录",401);
        }
        return true;
    }
}

添加 TokenConfig,设置需要过滤的接口信息,不在过滤中的接口都将配拦截校验是否存在token

@Configuration
public class TokenConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TokenHandle())
                .addPathPatterns("/**")
                .excludePathPatterns(
                        "/stu/register",
                        "/stu/login",
                        "/swagger-ui.html",
                        "/webjars/**",
                        "/swagger-resources/**"
                );
    }
}

测试

有如下接口:

http://localhost:9000/exam/saveExam

image-20230625153900273

在不加Token的情况下,或者Token已经过期的情况下, 发起请求,返回401

image-20230625154226048

现在生成一个Token,

image-20230625154504196

将得到的Token加在请求头中,再次发起请求

image-20230625154435476

可以看到本次请求正常返回200

补充:
如果项目中使用了Swagger,则在swagger中请求接口时也会被拦截器拦截,出现401提示,我们可以在swagger的配置类中添加请求头

package com.szx.exam.config;

import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.List;


/**
 * Swagger2配置信息
 */
@Configuration
@EnableSwagger2
public class Swagger2Config {

    @Bean
    public Docket webApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.szx.exam"))
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build();
    }

    public ApiInfo webApiInfo(){
        return new ApiInfoBuilder()
                .title("Api文档")
                .description("文本档描述了定义的接口")
                .version("1.0")
                .contact(new Contact("szx", "https://blog.csdn.net/SongZhengxing_?spm=1010.2135.3001.5343","2501954467@qq.com"))
                .build();
    }

    @Bean
    public Docket docket() {
        // 设置请求头
        List<Parameter> parameters = new ArrayList<>();
        parameters.add(new ParameterBuilder()
                .name("X-Token") // 字段名
                .description("添加请求头信息,校验是否登录") // 描述
                .modelRef(new ModelRef("string")) // 数据类型
                .parameterType("header") // 参数类型
                .defaultValue("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAKtWSq0oULIyNLM0MDEyMTc01FEqLU4t8kvMTVWyUno2t-_p7NlGSrUA1d5cpicAAAA.i6QU9I5h0hKHupiAK3JEfribAbQKRIXAYM4qUWR0PFGJenJUXz50aMMuxenUUBCsPI9-79m9JjB3SQLKc8xEOw") // 默认值:可自己设置
                .hidden(true) // 是否隐藏
                .required(false) // 是否必须
                .build());

        // 创建一个 swagger 的 bean 实例
        return new Docket(DocumentationType.SWAGGER_2)
                // 配置接口信息
                .select() // 设置扫描接口
                // 配置如何扫描接口
                .apis(RequestHandlerSelectors
                        .basePackage("com.szx.exam") // 扫描指定包下的接口,最为常用
                )
                .paths(PathSelectors
                        .any() // 满足条件的路径,该断言总为true
                )
                .build()
                .globalOperationParameters(parameters);
    }

}
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前端代码实现: 1. 登录成功后,将JWT Token存储在本地存储(LocalStorage)中: ```javascript localStorage.setItem('jwtToken', response.data.token); ``` 2. 在每次请求后端接口时,将JWT Token携带在请求头中: ```javascript axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('jwtToken'); axios.get('/api/userInfo') .then(response => { // 处理响应数据 }) .catch(error => { // 处理错误信息 }); ``` 3. 后端返回401 Unauthorized错误时,前端可以跳转到登录页重新登录: ```javascript axios.interceptors.response.use( response => response, error => { if (error.response.status === 401) { // 跳转到登录页 window.location.href = '/login'; } return Promise.reject(error); } ); ``` 后端代码实现: 1. 编写JWT Token校验拦截器: ```java public class JwtInterceptor implements HandlerInterceptor { @Autowired private JwtUtil jwtUtil; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 从请求头中获取JWT Token String token = request.getHeader("Authorization"); if (token != null && token.startsWith("Bearer ")) { token = token.substring(7); // 校验JWT Token是否有效 if (jwtUtil.validateToken(token)) { return true; } } // Token无效,返回401 Unauthorized错误 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; } } ``` 2. 将拦截器注册到拦截器链中: ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private JwtInterceptor jwtInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns("/**") // 拦截所有请求 .excludePathPatterns("/login"); // 排除登录请求 } } ``` 3. 在Controller中处理请求: ```java @RestController public class UserController { @GetMapping("/api/userInfo") public String getUserInfo() { // 处理请求 return "User Info"; } } ``` 需要注意的是,以上代码仅为示例代码,具体实现需要根据实际情况进行调整。同时,为了提高安全性,JWT Token需要设置过期时间,并定期更新Token。在前端实现JWT Token校验时,可以使用axios等HTTP请求库来发送请求,并设置请求头中的Authorization字段。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值