SpringBoot+JWT@注解实现token验证

原文链接:https://segmentfault.com/a/1190000022776284?utm_source=tag-newest

springboot集成jwt实现token验证
1、引入jwt依赖
    <!--jwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.9.0</version>
        </dependency>
2、自定义两个注解
/**
 * 忽略Token验证
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreAuth {
    boolean required() default true;
}
/**
 * 登录用户信息
 *
 */
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
    boolean required() default true;
}

@Target:注解的作用目标
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.METHOD)——方法
3、定义一个用户实体类

/**
 * 用户类
 *
 */

@Data
@ApiModel(value="User对象", description="用户表")
public class User extends BaseEntity<User> {

private static final long serialVersionUID=1L;

    @ApiModelProperty(value = "编号")
    private String id;

    @ApiModelProperty(value = "归属公司")
    private String companyId;

    @ApiModelProperty(value = "归属部门")
    private String officeId;

    @ApiModelProperty(value = "登录名")
    private String loginName;

    @ApiModelProperty(value = "密码")
    private String password;

    @ApiModelProperty(value = "工号")
    private String no;

    @ApiModelProperty(value = "姓名")
    private String name;

    @ApiModelProperty(value = "邮箱")
    private String email;

    @ApiModelProperty(value = "电话")
    private String phone;

    @ApiModelProperty(value = "手机")
    private String mobile;

    @ApiModelProperty(value = "用户类型")
    private String userType;

    @ApiModelProperty(value = "用户头像")
    private String photo;

    @ApiModelProperty(value = "最后登陆IP")
    private String loginIp;

    @ApiModelProperty(value = "最后登陆时间",example = "2019-11-22 00:00:00")
    private Date loginDate;

    @EnumFormat
    @ApiModelProperty(value = "登录状态 : 0 正常,1 异常")
    private UserLoginFlagEnum loginFlag;

    @ApiModelProperty(value = "创建者")
    private String createBy;

    @ApiModelProperty(value = "创建时间",example = "2019-11-22 00:00:00")
    private Date createDate;

    @ApiModelProperty(value = "更新者")
    private String updateBy;

    @ApiModelProperty(value = "更新时间",example = "2019-11-22 00:00:00")
    private Date updateDate;

    @ApiModelProperty(value = "备注信息")
    private String remarks;

    @TableLogic
    @ApiModelProperty(value = "删除标记")
    private String delFlag;

    @ApiModelProperty(value = "微信openid")
    private String openid;


    @Override
    protected Serializable pkVal() {
        return this.id;
    }

}
4、生成token
@Service("TokenService")
public class TokenService {
    public String getToken(User user) {
        String token="";
        token= JWT.create().withAudience(user.getId())// 将 user id 保存到 token 里面
                .sign(Algorithm.HMAC256(user.getOpenid()));// 以 OpenId 作为 token 的密钥
        return token;
    }
}
5、设置拦截器
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
    @Autowired
    IUserService userService;

    public static final String LOGIN_USER_KEY = "LOGIN_USER_KEY";


    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        //支持跨域请求
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with,X-Nideshop-Token,X-URL-PATH");
        httpServletResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));

        String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
        

        // 如果不是映射到方法直接通过
        if(!(object instanceof HandlerMethod)){
            return true;
        }
        HandlerMethod handlerMethod=(HandlerMethod)object;
        Method method=handlerMethod.getMethod();
        //检查是否有IgnoreAuth注释,有则跳过认证
        if (method.isAnnotationPresent(IgnoreAuth.class)) {
            IgnoreAuth passToken = method.getAnnotation(IgnoreAuth.class);
            if (passToken.required()) {
                return true;
            }
        }
        //检查有没有需要用户权限的注解
        if (method.isAnnotationPresent(LoginUser.class)) {
            LoginUser userLoginToken = method.getAnnotation(LoginUser.class);
            if (userLoginToken !=null) {
                // 执行认证
                if (token == null) {
                    throw new RuntimeException("无token,请重新登录");
                }
                // 获取 token 中的 user id
                String userId;
                try {
                    userId = JWT.decode(token).getAudience().get(0);
                } catch (JWTDecodeException j) {
                    throw new RuntimeException("401");
                }
                //设置userId到request里,后续根据userId,获取用户信息
                httpServletRequest.setAttribute(LOGIN_USER_KEY, userId);

                User user = userService.getById(userId);
                if (user == null) {
                    throw new RuntimeException("用户不存在,请重新登录");
                }
                // 验证 token
                JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getOpenid())).build();
                try {
                    jwtVerifier.verify(token);
                } catch (JWTVerificationException e) {
                    throw new RuntimeException("401");
                }
                return true;
            }
        }
        return true;
    }

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

    }
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,
                                HttpServletResponse httpServletResponse,
                                Object o, Exception e) throws Exception {
    }
}
6、配置拦截器

在配置类上添加了注解@Configuration,标明了该类是一个配置类并且会将该类作为一个SpringBean添加到IOC容器内

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**");   
    }
    @Bean
    public AuthenticationInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }
}
7、token验证流程

1、用户登录是生成token
2、从http请求头中取出token
3、判断是否映射到方法
4、检查是否有@IgnoreAuth注释,有则跳过认证
5、检查是否有用户登录的注解,有则需要取出并验证
6、认证通过则可以访问

  1. public class JWTUtil {  
  2.     public static final String SECRET_KEY = "123456"; //秘钥  
  3.     public static final long TOKEN_EXPIRE_TIME = 5 * 60 * 1000; //token过期时间  
  4.     public static final long REFRESH_TOKEN_EXPIRE_TIME = 10 * 60 * 1000; //refreshToken过期时间  
  5.     private static final String ISSUER = "issuer"; //签发人  
  6.   
  7.     /** 
  8.      * 生成签名 
  9.      */  
  10.     public static String generateToken(String username){  
  11.         Date now = new Date();  
  12.         Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY); //算法  
  13.           
  14.         String token = JWT.create()  
  15.             .withIssuer(ISSUER) //签发人  
  16.             .withIssuedAt(now) //签发时间  
  17.             .withExpiresAt(new Date(now.getTime() + TOKEN_EXPIRE_TIME)) //过期时间  
  18.             .withClaim("username", username) //保存身份标识  
  19.             .sign(algorithm);  
  20.         return token;  
  21.     }  
  22.       
  23.     /** 
  24.      * 验证token 
  25.      */  
  26.     public static boolean verify(String token){  
  27.         try {  
  28.             Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY); //算法  
  29.             JWTVerifier verifier = JWT.require(algorithm)  
  30.                     .withIssuer(ISSUER)  
  31.                     .build();  
  32.             verifier.verify(token);  
  33.             return true;  
  34.         } catch (Exception ex){  
  35.             ex.printStackTrace();  
  36.         }  
  37.         return false;  
  38.     }  
  39.       
  40.     /** 
  41.      * 从token获取username 
  42.      */  
  43.     public static String getUsername(String token){  
  44.         try{  
  45.             return JWT.decode(token).getClaim("username").asString();  
  46.         }catch(Exception ex){  
  47.             ex.printStackTrace();  
  48.         }  
  49.         return "";  
  50.     }  
  51. }  
原文地址:https://www.cnblogs.com/fswhq/p/13634248.html