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)@Documentedpublic @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、设置拦截器
@Componentpublic 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容器内

@Configurationpublic 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、认证通过则可以访问