springboot 集成jwt 登录 拦截器获取token 解析token放入holder中

发布时间 2023-11-17 17:59:47作者: 蜗牛无敌

一、依赖

 

  <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.11.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.32</version>
        </dependency>
    </dependencies>

 二、工具类

package com.example.demo.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.example.demo.contant.RequestKeyConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class JWTUtils {

    // token 签名的秘钥,可设置到配置文件中
    private static final String SECRET_KEY = "secretKey:123456";
    // token过期时间
    public static final long TOKEN_EXPIRE_TIME = 7200 * 1000;

    /**
     * 生成jwt
     */
    public static String createJwt(String userId) {
        Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
        //设置头信息
        HashMap<String, Object> header = new HashMap<>(2);
        header.put("typ", "JWT");
        header.put("alg", "HS256");
        // 生成 token:头部+载荷+签名
        return JWT.create().withHeader(header)
                .withClaim(RequestKeyConstants.USER_ID, userId)
                .withExpiresAt(new Date(System.currentTimeMillis() + TOKEN_EXPIRE_TIME)).sign(algorithm);
    }

    public static Map<String, Claim> parseJwt(String token) {
        Map<String, Claim> claims = null;
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            claims = jwt.getClaims();
            return claims;
        } catch (Exception e) {
            log.error("jwt token  {} 解析异常",token);
            return null;
        }
    }

    /**
     * 解析jwt
     */
    public static Long getUserId(String token) {
        try {
            Map<String, Claim> claims = parseJwt(token);
            if (claims != null) {
                String userId = claims.get(RequestKeyConstants.USER_ID).asString();
                if (StringUtils.hasLength(userId)) {
                    return Long.valueOf(userId);
                }
            }
        } catch (Exception e) {
            log.error("jwt token  {} 解析异常",token);
        }
        return null;
    }
}

 三、拦截器

package com.example.demo.intercept;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.interfaces.Claim;
import com.example.demo.contant.RequestKeyConstants;
import com.example.demo.util.JWTUtils;
import com.example.demo.util.RequestContext;
import com.example.demo.util.UserLoginContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;


import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class RequestProcessInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");
        if(!StringUtils.hasLength(token)) {
            token = request.getParameter("token");
        }
        if(!StringUtils.hasLength(token)){
            Map<String,Object> map = new HashMap<>();
            map.put("err",100);
            map.put("msg","请先登录");

            String json = JSONObject.toJSONString(map);
            //设置响应头(告知浏览器:响应的数据类型为json、响应的数据编码表为utf-8)
            response.setContentType("application/json;charset=utf-8");
            //响应
            response.getWriter().write(json);
            return false;//不放行
        }

        //5.解析token,如果解析失败,返回错误结果(未登录)
        try {
            Long userId = JWTUtils.getUserId(token);//获取用户的基本信息

            RequestContext context = UserLoginContextHolder.get() == null ? new RequestContext() : UserLoginContextHolder.get();
            this.setCookies(request, context);
            context.setUserId(Long.valueOf(userId));
            UserLoginContextHolder.set(context);

        }catch (Exception e){
            Map<String,Object> map = new HashMap<>();
            map.put("err",101);
            map.put("msg","token不正确");
            String json = JSONObject.toJSONString(map);
            //设置响应头
            response.setContentType("application/json;charset=utf-8");
            //响应
            response.getWriter().write(json);
            return false;
        }

        //6.放行
        return true;
    }

    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }

    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        UserLoginContextHolder.remove();
        ThreadContext.clearAll();
    }

    private void setCookies(HttpServletRequest request, RequestContext requestContext) {
        Cookie[] cookies = request.getCookies();
        requestContext.setCookies(cookies);
    }

}
package com.example.demo.contant;

public class RequestKeyConstants {

   public static final String USER_ID="curr_user_id";
}

·当前用户信息承载类

package com.example.demo.util;

import lombok.Data;

import javax.servlet.http.Cookie;

@Data
public class RequestContext {
    private Long userId; //当前用户ID
    private String deviceId; //设备id
    private String deviceType; //设备类型
    private String appVersion; //APP版本
    private String ip;//客户端IP
    private String requestId;
    private Cookie[] cookies;
}
package com.example.demo.util;


public class UserLoginContextHolder {
    private static final InheritableThreadLocal<RequestContext> REQUEST_CONTEXT_INHERITABLE_THREAD_LOCAL = new InheritableThreadLocal();

    public UserLoginContextHolder() {
    }

    public static RequestContext get() {
        return (RequestContext)REQUEST_CONTEXT_INHERITABLE_THREAD_LOCAL.get();
    }

    public static void set(RequestContext context) {
        REQUEST_CONTEXT_INHERITABLE_THREAD_LOCAL.set(context);
    }

    public static void remove() {
        REQUEST_CONTEXT_INHERITABLE_THREAD_LOCAL.remove();
    }
}
package com.example.demo.config;

import com.example.demo.intercept.RequestProcessInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RequestProcessInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/register", "/image/**", "/js/**", "/css/**")
                .order(0);
    }
}
package com.example.demo.controller;

import com.example.demo.util.JWTUtils;
import com.example.demo.util.RequestContext;
import com.example.demo.util.UserLoginContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;

@RestController
@Slf4j
public class LoginController {

    @RequestMapping("/login")
    public String create(@RequestParam("userId") Long userId) {
        String token = JWTUtils.createJwt(userId + "");
        return token;
    }

    @RequestMapping("/auth/parse")
    public RequestContext parse() {
        RequestContext requestContext = UserLoginContextHolder.get();
        Cookie[] cookies = requestContext.getCookies();
        StringBuilder sb = new StringBuilder();
        for (Cookie cookie : cookies) {
           sb.append(cookie.getName());
           sb.append("====");
           sb.append(cookie.getValue());
           sb.append("\r\n");
        }
        log.info(sb.toString());

        return requestContext;
    }
}