Springboot实现可靠的JWT校验全流程

本文实现了对指定url批量校验token,采用JWT方式,登录成功将jwttoken传入到前端,前端保存jwttoken到缓存中,请求其他接口时,将jwttoken通过header携带,服务端通过header中的token校验前端的用户身份以及请求的合法性。 首先要定义一个JWTKEY,建议创建一个Constract类,定义一些常量,这个KEY作为JWT生成校验位所用密钥,在解析用户传入token时,也可token的校验合法性。 具体实现需要先引入jwt校验支持和切面通知AOP支持。

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.3.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

首先介绍下,如何生成JWTToken

//userId为携带的用户身份ID,Constant.JWT_KEY为设定的JWT加解密key常量,Constant.EXPIRE_TIME为token有效期
Algorithm algorithm=Algorithm.HMAC256(Constant.JWT_KEY);
        String token= JWT.create()
                .withClaim(Constant.USER_ID,userId)
                .withClaim(Constant.USER_ROLE,1)
                .withExpiresAt(new Date(System.currentTimeMillis()+Constant.EXPIRE_TIME))
                .sign(algorithm);

在其他需要校验登录身份的接口中,需要一个AOP切面通知,来实现校验,一个demo:

package wang.aweb.childcarpackage wang.aweb.childcar.filter;

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.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import wang.aweb.childcar.common.Constant;
import wang.aweb.childcar.exception.CarException;
import wang.aweb.childcar.exception.CarExceptionEnum;
import wang.aweb.childcar.model.pojo.Member;
import wang.aweb.childcar.service.MemberService;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

public class UserFilter implements Filter {
    private static final List<String> ALLOWED_PATHS=Arrays.asList("/api/user/login");
    @Autowired
    private MemberService memberService;
    public static ThreadLocal<Member> memberThreadLocal=new ThreadLocal();
    public Member currentUser=new Member();

    public Member getCurrentUser() {
        return currentUser;
    }

    public void setCurrentUser(Member currentUser) {
        this.currentUser = currentUser;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request=(HttpServletRequest) servletRequest;
        String token=request.getHeader(Constant.JWT_TOKEN);
        String path=request.getRequestURI().substring(request.getContextPath().length()).replaceAll("[/]+$","");
        Boolean allowPath=ALLOWED_PATHS.contains(path);
        if(allowPath==false){
            if(token==null){
                PrintWriter out=new HttpServletResponseWrapper((HttpServletResponse)servletResponse).getWriter();
                out.write("{\n" +
                        "    \"code\": 10007,\n" +
                        "    \"msg\": \"NEED_JWT_TOKEN\",\n" +
                        "    \"data\": null\n" +
                        "}");
                out.flush();
                out.close();
                return;
            }

            Algorithm algorithm=Algorithm.HMAC256(Constant.JWT_KEY);

            JWTVerifier jwtVerifier= JWT.require(algorithm).build();
            try{
                DecodedJWT jwt=jwtVerifier.verify(token);
                currentUser=new Member();
                currentUser.setId(jwt.getClaim(Constant.USER_ID).asInt());
                memberThreadLocal.set(currentUser);
            }catch (TokenExpiredException e){
                throw new CarException(CarExceptionEnum.TOKEN_EXPIRED);
            }catch (JWTDecodeException e){
                throw new CarException(CarExceptionEnum.TOKEN_WRONG);
            }catch (Exception e){
                throw new CarException(CarExceptionEnum.SYSTEM_ERROR);
            }
        }

        filterChain.doFilter(servletRequest,servletResponse);
    }
    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
.filter;

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.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import wang.aweb.childcar.common.Constant;
import wang.aweb.childcar.exception.CarException;
import wang.aweb.childcar.exception.CarExceptionEnum;
import wang.aweb.childcar.model.pojo.Member;
import wang.aweb.childcar.service.MemberService;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

public class UserFilter implements Filter {
    private static final List<String> ALLOWED_PATHS=Arrays.asList("/api/user/login");
    @Autowired
    private MemberService memberService;
    public static ThreadLocal<Member> memberThreadLocal=new ThreadLocal();
    public Member currentUser=new Member();

    public Member getCurrentUser() {
        return currentUser;
    }

    public void setCurrentUser(Member currentUser) {
        this.currentUser = currentUser;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request=(HttpServletRequest) servletRequest;
        String token=request.getHeader(Constant.JWT_TOKEN);
        String path=request.getRequestURI().substring(request.getContextPath().length()).replaceAll("[/]+$","");
        Boolean allowPath=ALLOWED_PATHS.contains(path);
        if(allowPath==false){
            if(token==null){
                PrintWriter out=new HttpServletResponseWrapper((HttpServletResponse)servletResponse).getWriter();
                out.write("{\n" +
                        "    \"code\": 10007,\n" +
                        "    \"msg\": \"NEED_JWT_TOKEN\",\n" +
                        "    \"data\": null\n" +
                        "}");
                out.flush();
                out.close();
                return;
            }

            Algorithm algorithm=Algorithm.HMAC256(Constant.JWT_KEY);

            JWTVerifier jwtVerifier= JWT.require(algorithm).build();
            try{
                DecodedJWT jwt=jwtVerifier.verify(token);
                currentUser=new Member();
                currentUser.setId(jwt.getClaim(Constant.USER_ID).asInt());
                memberThreadLocal.set(currentUser);
            }catch (TokenExpiredException e){
                throw new CarException(CarExceptionEnum.TOKEN_EXPIRED);
            }catch (JWTDecodeException e){
                throw new CarException(CarExceptionEnum.TOKEN_WRONG);
            }catch (Exception e){
                throw new CarException(CarExceptionEnum.SYSTEM_ERROR);
            }
        }

        filterChain.doFilter(servletRequest,servletResponse);
    }
    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

评论

(= ̄ω ̄=)··· 暂无内容!

回复

您还未登录,请先登录或者注册