spring boot JWT token 验证及传递用户信息

第一步 集成jwt

  1. 添加jwt 依赖
		<dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.0</version>
        </dependency>
  1. 定义TokenUser
import lombok.Data;

/**
 * @author fengrz
 */
@Data
public class TokenUser {

    String userId;
    String userName;
}

  1. 定义接口
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import org.springframework.beans.factory.annotation.Value;
import java.util.Date;
public interface IJavaWebTokenService {

    /**
     * 根据用户名称生成签名
     * @param userId
     * @param userName
     * @return token
     */
    String sign(String userId,String userName) throws Exception;

    /**
     * 签名验证
     * @param userId
     * @param token
     * @return true or false
     */
    TokenUser verify(String userId,String token) throws Exception;

}

  1. 实现token生成及验证方法
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.goldnurse.commons.security.IJavaWebTokenService;
import com.goldnurse.commons.security.TokenUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
@Slf4j
@Service
public class JavaWebTokenServiceImpl implements IJavaWebTokenService {

    /**
     * 过期时间
     */
    @Value("${goldnurse.commons.config.jwt.expire-time}")
    private long expireTime;

    /**
     * token 加密串
     */
    @Value("${goldnurse.commons.config.jwt.token-secret}")
    private  String tokenSecret;


    /**
     * 根据用户名称生成签名
     * @param userId
     * @param userName
     * @return token
     */
    @Override
    public String sign(String userId,String userName){
        if(StringUtils.isEmpty(userId)){
            log.error(" userId is null ");
            return null;
        }
        if(StringUtils.isEmpty(userName)){
            log.error(" userName is null ");
            return null;
        }

        long eTime = expireTime*24*60*60*1000L;
        String token = null;
        try {
            Date expiresAt = new Date(System.currentTimeMillis() + eTime);
            token = JWT.create()
                    .withIssuer(userId)
                    .withClaim("username", userName)
                    .withExpiresAt(expiresAt)
                    // 使用了HMAC256加密算法。
                    .sign(Algorithm.HMAC256(tokenSecret));
        } catch (Exception e){
            e.printStackTrace();
        }
        return token;

    }

    /**
     * 签名验证
     * @param userId
     * @param token
     * @return true or false
     */
    @Override
    public TokenUser verify(String userId, String token) throws Exception{
        if(StringUtils.isEmpty(userId)){
            log.error(" userId is null ");
            return null;
        }
        if(StringUtils.isEmpty(token)){
            log.error(" token is null ");
            return null;
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(tokenSecret)).withIssuer(userId).build();
            DecodedJWT jwt = verifier.verify(token);
            TokenUser tokenUser = new TokenUser();
            tokenUser.setUserId(userId);
            tokenUser.setUserName(jwt.getClaim("username").asString());
            log.debug("认证通过:"+jwt.getIssuer()+" - "+ jwt.getClaim("username").asString() + " - " + sdf.format(jwt.getExpiresAt()));
            return tokenUser;
        } catch (Exception e){
            e.printStackTrace();
            throw e;
        }

    }


}

  1. application.yml 中添加配置信息
goldnurse:
  commons:
    config:
      jwt:
        expire-time: 20 # day
        token-secret: 9838383838383838383838
        excluded-urls: /survey/user/login,/survey/user/getAll

第二步 配置 TokenFilter

  1. 创建 TokenRequestWrapper

当controller 方法需要tokenUserId,tokenUserName 时,赋值

import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

@Slf4j
public class TokenRequestWrapper extends HttpServletRequestWrapper {

    private TokenUser tokenUser;

    public TokenRequestWrapper(HttpServletRequest request){
        super(request);
    }

    public TokenRequestWrapper(HttpServletRequest request,TokenUser tokenUser1){
        super(request);
        tokenUser = tokenUser1;
    }

    @Override
    public String[] getParameterValues(String name) {
        if ("tokenUserName".equals(name)){
            return new String[]{tokenUser.getUserName()};
        }
        if ("tokenUserId".equals(name)){
            return new String[]{tokenUser.getUserId()};
        }
        return super.getParameterValues(name);
    }

}

  1. 创建 TokenFilter

import com.goldnurse.commons.security.IJavaWebTokenService;
import com.goldnurse.commons.security.TokenRequestWrapper;
import com.goldnurse.commons.security.TokenUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
@WebFilter(urlPatterns = "/*",filterName = "tokenFilter")
public class TokenFilter implements Filter {

    @Value("${goldnurse.commons.config.jwt.excluded-urls}")
    private String excludedUrls;
    @Resource
    IJavaWebTokenService iJavaWebTokenService;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        if(!check(request.getRequestURL().toString())) {
            String userId = request.getHeader("userId");
            String token = request.getHeader("token");
            if(StringUtils.isEmpty(userId)){
                log.error("Token 验证,参数 userId 不允许为空 ");
                return;
            }
            if(StringUtils.isEmpty(token)){
                log.error("Token 验证,参数 token 不允许为空");
                return;
            }

            TokenUser tokenUser = null;
            try {
                tokenUser = iJavaWebTokenService.verify(userId, token);
                if (tokenUser != null) {
                    filterChain.doFilter(new TokenRequestWrapper(request, tokenUser), response);
                }
            } catch (Exception e) {
                log.error("Token 验证失败,请检查是否正确");
                return;
            }

        }else{
            filterChain.doFilter(request,response);
        }
    }

    @Override
    public void destroy() {

    }

    /**
     * 检查url 是否需要做token验证
     * @param url
     * @return 需要时,返回 true
     */
    public boolean check(String url){

        if(excludedUrls == ""){
            log.debug("goldnurse.commons.config.jwt.excluded-urls - is null");

        }else {
            String[] urls = excludedUrls.split(",");
            for (String eurl: urls) {
                if(url.contains(eurl)){
                    return true;
                }
            }
        }
        return false;
    }

}
  1. application.yml
  • expire-time 过期时间
  • token-secret 加密串
  • excluded-urls 排除的url,不需要做token校验
goldnurse:
  commons:
    config:
      jwt:
        expire-time: 20 # day
        token-secret: 9999999999
        excluded-urls: /survey/user/login,/survey/user/getAll
  1. 主函数中添加 @ServletComponentScan

在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码。

@EnableTransactionManagement
@SpringBootApplication
@EnableAsync
@ServletComponentScan
public class SurveyWebApplication {

    public static void main(String[] args) {
        SpringApplication.run(SurveyWebApplication.class, args);
    }

}

第三步 测试

  1. 在controller 中添加测试方法

如果方法体中需要token 解析出来的tokenUserId,tokenUserName ,只需在方法参数上增加
String tokenUserId,String tokenUserName

	@PostMapping(name = "测试",path = "/test")
    public String test(String name, String email,String tokenUserId,String tokenUserName)  {

        log.debug(tokenUserId +" "+ tokenUserName);
        return "error";
    }
  1. 使用postman 测试接口,在Headers 中增加userId和token
    spring boot JWT token 验证及传递用户信息_第1张图片
  2. 访问接口,查看日志输出,显示正常,测试成功

你可能感兴趣的:(java,springboot)