后端开发Springboot个人使用最小应用-jwt通过配置完成登录验证

27 篇文章 0 订阅

1. application配置属性

#安全验证jwt
jwt.header=Authorization
#令牌前缀,前后端发送token添加上此令牌
jwt.token-start-with=Bearer
#令牌签名
jwt.sing=!@#$/*-QRIU234^&^Y*

2. 获取属性的实体对象

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//从配置文件中获取jwt关键字段
@Data
@Component
public class JWTProperty {

    @Value("${jwt.header}")
    private String tokenHeader;

    @Value("${jwt.token-start-with}")
    private String tokenStartWith;

    @Value("${jwt.sing}")
    private String sing ;

}

3. jwt工具类

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.march.system.utils.property.JWTProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Calendar;
import java.util.Map;
@Slf4j
@Component
public class JWTUtils {

    //获取token时,获取jwt配置信息,
    @Autowired
    private  JWTProperty jwtProperty ;
    
    @Value("${jwt.sing}")
    private String sing ;
    
    private static ThreadLocal<Object> requestUserThreadLocal = new ThreadLocal<>();

    //验证合法性时,由调用者(拦截器)传递
    public JWTUtils(JWTProperty jwtProperty){
        this.jwtProperty = jwtProperty;
    }

    public JWTUtils () {}

    //生成token
    public  String getToken(Map<String, Object> map) {
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE, 7);  //七天过期
        JWTCreator.Builder builder = JWT.create();
        map.forEach((K, V) -> {
                    builder.withClaim(K, V.toString());
        });
        return builder
                .withExpiresAt(instance.getTime())
                .sign(Algorithm.HMAC256(jwtProperty.getSing()));
    }
     // 验证token合法性
    public DecodedJWT verify(String token) {
        this.sing = jwtProperty.getSing();
        return  JWT.require(Algorithm.HMAC256(jwtProperty.getSing())).build().verify(token);
    }

    //将token存储在当前线程
    public  void setThreadLocalToken(String token) {
        requestUserThreadLocal.set(token);
    }
    //从当前线程中获取token
    public  String getThreadLocalToken() {
        return requestUserThreadLocal.get().toString();
    }
    //获取DecodedJWT(解码后的token)
    public  DecodedJWT getThreadLocalDecodedJWT() {
        String token = getThreadLocalToken();
        return JWT.require(Algorithm.HMAC256(jwtProperty.getSing())).build().verify(token);
    }
    //清空
    public  void removeThreadLocal() {
        requestUserThreadLocal.remove();
    }


    //获取当前登录对象id
    public  Long getThreadLocalUserId(){
        DecodedJWT verify = getThreadLocalDecodedJWT();
        Integer type = getThreadLocalType();
        Long userId = null;
            userId  = Long.parseLong(verify.getClaim("userId").asString());
        return userId;
    }
}

4. 登录接口,调用生成token

		private final JWTUtils jwtUtils;
		……
	
		Map<String,Object> map = new HashMap<>();
		// token存储当前用户id
        map.put("bloggerId",blogger.getBloggerId());
        String token = jwtUtils.getToken(map);
        //将token存储在当前线程中
		jwtUtils.removeThreadLocal();
        jwtUtils.setThreadLocalToken(token);
        //封装token   "Authorization": "Bearer YWxhZGRpbjpvcGVuc2VzYW1l"
        Map<String ,String> tokenMap = new HashMap<>();
        tokenMap.put(jwtProperty.getTokenHeader(),jwtProperty.getTokenStartWith()+" "+token);

5. 控制是否需要登录验证的注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//使用该注解表示类或方法必须进行token验证
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface VerifyToken {
}

对于某一个接口,如果需要进行登录验证,那么就对其使用这个注解
例如:

 	@DeleteMapping
    @VerifyToken
    public Result deleteUser(Long id) {
……
}

6. jwt验证拦截器
配置一个继承HandlerInterceptor的拦截器,用来验证请求是否带有token,且token是否有效。

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.exceptions.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.march.system.utils.annution.VerifyToken;
import com.march.system.utils.property.JWTProperty;
import com.march.system.utils.JWTUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class JWTInterceptor implements HandlerInterceptor {
    private  JWTProperty jwtProperty ; //实体类,用来获取配置文件application中关于jwt的配置,其中使用 @Value("${jwt.header}") 来获取值

    //jwt工具类,见上面
    private  JWTUtils jwtUtils ;
	
	//这里是没有Bean引入的,在别的地方通过对象引入。注意new的对象是一个全新的、独立的对象
    public JWTInterceptor(JWTProperty jwtProperty,JWTUtils jwtUtils){
        this.jwtProperty = jwtProperty;
        this.jwtUtils = jwtUtils;
    }
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map<String,Object> map = new HashMap<>();
        response.setContentType("application/json;charset=UTF-8");
        String json =null;
        //获取请求头中令牌
        Enumeration<String> headerNames = request.getHeaderNames();
        String token = request.getHeader("authorization");
        //如果不是映射到Controller直接放行 
        if(!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod)handler;
        Method method = handlerMethod.getMethod();
        //自定义注解,判断当前请求是否需要验证
        // 如果当前请求方法添加@VerifyToken注解
        if(method.isAnnotationPresent(VerifyToken.class)){
            //判断token不为空,长度不为0,非空白符,且包含字符串startWith
            if(StrUtil.isNotEmpty(token) && token.startsWith(jwtProperty.getTokenStartWith())) {
                //判断token是否只有前缀没有身体
                if(token.length() <= (jwtProperty.getTokenStartWith().length()+1)) {
                    return false;
                }
                //切除token前缀
                token = token.substring(jwtProperty.getTokenStartWith().length()+1);
                log.info("【切除后token="+token+"】");
                if(StrUtil.isNotEmpty(token)){
                    try{
                        //检验token是否合法
                        jwtUtils.verify(token);
                        jwtUtils.setThreadLocalToken(token);
                        return true;
                    }catch (SignatureVerificationException | InvalidClaimException | AlgorithmMismatchException | TokenExpiredException e) {
                        e.printStackTrace();
                        map.put("message","您还没有登录,请先登录");
                    }
                    map.put("code",401);
                    json = new ObjectMapper().writeValueAsString(map);
                    response.getWriter().println(json);
                    return false;
                }
            }
            map.put("message","您还没有登录,请先登录");
            map.put("code",401);
            json = new ObjectMapper().writeValueAsString(map);
            response.getWriter().println(json);
            return false;
        }
        return true;
    }
}

7. 拦截器需要注册在MVC中,并指明需要拦截的目标

import com.march.system.utils.JWTUtils;
import com.march.system.utils.property.JWTProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig  implements WebMvcConfigurer {
    //从配置文件中获取JWT全局使用重点词
    @Autowired
    private JWTProperty jwtProperty;
    //关于jwt的工具类
    @Autowired
    private  JWTUtils jwtUtils ;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor(jwtProperty,jwtUtils))
            //非拦截接口:登录,注册,注册时发送邮箱
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/**/verify")
                .excludePathPatterns("/api/**/register")
        .excludePathPatterns("/api/*/login");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值