天天看点

springboot中整合JWT Token

springboot中整合JWT Token

1、pom.xml中引入

<!--jwt token-->
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt</artifactId>
  <version>0.9.1</version>
</dependency>
           

2、application.yml中配置

jwt:
  # 加密密钥
  secret: jellymilk
  # token有效时长  1小时:3600  1天:86400
  expire: 3600
  # header 名称
  header: Authorization
  #发行人
  issuer: cbyzs
  #忽略token验证的 请求
  ignores:
    - /login/token
    - /static/**
           

3、JwtProperties属性配置bean

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
 
import java.util.List;
 
/**
 * jwt配置参数信息
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "jwt")
public class JwtProperties {
 
    private String  secret;//加密密钥
    private Long   expire; // token有效期 秒
    private String header;// token 采用的http头,一般使用: Authorization
    private String  issuer;//发行人
 
    private List<String> ignores; //忽略token的页面
 
}
           

JwtTokenIgnore 注解,请求忽略token验证

import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface JwtTokenIgnore {
 
}
           

4、Token的web拦截器

import cn.cbyzs.ssdemo.common.exception.BusinessException;
import cn.hutool.core.util.StrUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
 
@Component
public class JwtTokenInterceptor extends  HandlerInterceptorAdapter {
 
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
 
 
    private  AntPathMatcher antPathMatcher = new AntPathMatcher();
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
 
        // 如果不是映射到方法直接通过
        if(!(handler instanceof HandlerMethod)){
            return true;
        }
        //controller的方法上标记了 JwtTokenIgnore 注解的方法,直接放行
        HandlerMethod handlerMethod=(HandlerMethod)handler;
        Method method=handlerMethod.getMethod();
 
        if(method.isAnnotationPresent(JwtTokenIgnore.class)){
            return true;//放行
        }
 
        JwtProperties props= jwtTokenUtil.getJwtProperties();
        List<String> ignores =props.getIgnores();
 
        String contextPath=request.getContextPath();
        String uri=request.getRequestURI();
        String path=uri.replaceFirst(contextPath, "").replaceAll("/+", "/");
 
        //ignores 忽略的请求 ,放行
        for (String pattern : ignores) {
           if (antPathMatcher.match(pattern, path)) {
               return true;//放行
           }
        }
 
        String token = request.getHeader(props.getHeader());
        if(StrUtil.isEmpty(token)){
            throw new BusinessException(3000,"token不能为空");
        }
 
        Claims claims = jwtTokenUtil.parseJWT(token);
        if(claims.getExpiration().before(new Date())){
            throw new BusinessException(3000,"token已过期,请重新获取");
        }
 
        request.setAttribute("identityId", claims.getSubject());//设置用户凭证id
        return true;
    }
}
           

WebConfig 配置,添加注册拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {
 
    @Autowired
    private JwtTokenInterceptor tokenInterceptor ;
 
    /**
     * 配置全站允许CORS跨域访问
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*") //允许的来源域  如http://www.demo.com
                .allowedMethods("GET", "POST","PUT","DELETE","PATCH")
                .allowCredentials(false).maxAge(3600);
    }
 
 
 
    /**
     * 配置web拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**");
    }
 
}
           

5、JwtTokenUtil 工具bean

import cn.cbyzs.ssdemo.common.exception.BusinessException;
import cn.hutool.core.util.StrUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
 
import javax.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.Date;
 
@Configuration
@EnableConfigurationProperties(JwtProperties.class)
@Slf4j
public class JwtTokenUtil {
 
    @Autowired
    private JwtProperties jwtProperties;
 
    public JwtProperties getJwtProperties() {
        return jwtProperties;
    }
 
    public String getSecretKey(){
        return Base64.getEncoder().encodeToString(jwtProperties.getSecret().getBytes());
 
    }
 
 
    /**
     * 生成token
     * @param subject 一般为用户名
     * @return
     */
    public String createToken (String subject){
 
        String secret =jwtProperties.getSecret();//密钥
        long expire= jwtProperties.getExpire();//过期失效
        String issuer = jwtProperties.getIssuer();//发行人
 
        Date nowDate = new Date();
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);//过期时间
 
        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(subject)//主题
                .setIssuer(issuer)//发行人
                .setIssuedAt(nowDate) //发行时间
                .setExpiration(expireDate)//过期时间
                //.setClaims()
                .signWith(SignatureAlgorithm.HS256, getSecretKey())// 签名部分
                .compact();
    }
 
    /**
     * 获取token中注册信息 (body信息)
     * @param token
     * @return
     */
    public Claims parseJWT (String token) {
        try {
            if(StrUtil.isEmpty(token)){
                throw new BusinessException(3000,"token不能为空");
            }
            String secret =getSecretKey();//密钥
            return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        }catch (Exception e){
            log.error(e.getMessage(),e);
            throw new BusinessException(3000,"验证token失败");
        }
    }
 
 
    /**
     * 从http请求中获取http的token头
     * @return
     */
    public String getHttpToken(){
        HttpServletRequest request = ((ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes()).getRequest();
        String token= request.getHeader(jwtProperties.getHeader());
 
        return token;
    }
 
    public Claims getTokenClaims(){
        String token = getHttpToken();
        return parseJWT(token);
    }
 
    public String  getTokenClaimsSubject(){
        String token = getHttpToken();
        Claims claims=  parseJWT(token);
        return claims.getSubject();
 
    }
 
 
}
           

6、LoginController.java 登录token、刷新token、从token中获取用户信息

import cn.cbyzs.ssdemo.common.RetMsg;
import cn.cbyzs.ssdemo.common.jwt.JwtTokenUtil;
import cn.cbyzs.ssdemo.user.model.User;
import cn.cbyzs.ssdemo.user.service.LoginService;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.HashMap;
import java.util.Map;
 
 
@RestController
@RequestMapping("/login")
public class LoginController {
 
    @Autowired
    private LoginService loginService;
 
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
 
    /**
     * 登录获取token
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @RequestMapping("/token")
    public RetMsg token(String username,String password){
        User user= loginService.login(username,password);
        if(user!=null){ //说明登录成功
            String token= jwtTokenUtil.createToken(user.getUsername());
            Claims claims= jwtTokenUtil.parseJWT(token);//jwt主体
 
            Map<String,Object> data=new HashMap<>();
            data.put("user",user);
            data.put("token",token);
            data.put("expire",claims.getExpiration());
            return RetMsg.success(data);//下发token和用户信息
        }
        return RetMsg.failure("用户登录失败");
    }
 
    /**
     * 刷新token  获取新的token
     * @return
     */
    @RequestMapping("/refreshToken")
    public RetMsg  refreshToken(){
        String username= jwtTokenUtil.getTokenClaimsSubject();
         //生成新的token
        String newToken = jwtTokenUtil.createToken(username);
        return RetMsg.success(newToken) ;
 
    }
 
    /**
     * 获取用户信息,从token中获取到username
     * @return
     */
    @RequestMapping("/getUserInfo")
    public  RetMsg getUserInfo(){
        String username= jwtTokenUtil.getTokenClaimsSubject();
        User user=  loginService.findUserByUsername(username);
        return RetMsg.success(user);
    }
 
}
           

继续阅读