zoukankan      html  css  js  c++  java
  • 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. }  
  • 相关阅读:
    Hadoop 学习笔记 (十) hadoop2.2.0 生产环境部署 HDFS HA Federation 含Yarn部署
    hadoop 2.x 安装包目录结构分析
    词聚类
    Hadoop 学习笔记 (十一) MapReduce 求平均成绩
    Hadoop 学习笔记 (十) MapReduce实现排序 全局变量
    Hadoop 学习笔记 (九) hadoop2.2.0 生产环境部署 HDFS HA部署方法
    Visual Studio Code 快捷键大全(Windows)
    Eclipse安装教程 ——史上最详细安装Java &Python教程说明
    jquery操作select(取值,设置选中)
    $.ajax 中的contentType
  • 原文地址:https://www.cnblogs.com/fswhq/p/13634248.html
Copyright © 2011-2022 走看看