美文网首页
个人博客开发之blog-api 项目整合JWT实现token登录

个人博客开发之blog-api 项目整合JWT实现token登录

作者: 程序员三时 | 来源:发表于2021-07-21 09:36 被阅读0次

    前言

    现在前后端分离,基于session设计到跨越问题,而且session在多台服器之前同步问题,肯能会丢失,所以倾向于使用jwt作为token认证 json web token

    1. 导入java-jwt工具包
     <dependency>
                <groupId>com.auth0</groupId>
                <artifactId>java-jwt</artifactId>
                <version>3.15.0</version>
            </dependency>
    
    1. 通过jwt生成token

    编写通用TokenService

    package cn.soboys.core.authentication;
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.algorithms.Algorithm;
    import org.springframework.stereotype.Service;
    
    import java.util.Date;
    
    /**
     * @author kenx
     * @version 1.0
     * @date 2021/6/22 10:23
     * token 操作
     */
    @Service("TokenService")
    public class TokenService {
    
        //过期时间单位 毫秒 7*24*60*60*1000
        private final Long tokenExpirationTime = 604800000l;
    
        /**
         * @param uuid   用户唯一标示
         * @param secret 用户密码等
         * @return token生成
         */
        public String generateToken(String uuid, String secret) {
            //每次登录充当前时间重新计算
            Date expiresDate = new Date(System.currentTimeMillis() + tokenExpirationTime);
            String token = "";
            token = JWT.create()
                    //设置过期时间
                    .withExpiresAt(expiresDate)
                    //设置接受方信息,一般时登录用户
                    .withAudience(uuid)// 将 user id 保存到 token 里面
                    //使用HMAC算法
                    .sign(Algorithm.HMAC256(secret));// 以 password 作为 token 的密钥
            return token;
        }
    }
    
    
    1. 编写注解过滤拦截需要登录验证的controller

    PassToken用于跳过登录验证UserLoginToken表示需要登录验证

    package cn.soboys.core.authentication;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @author kenx
     * @version 1.0
     * @date 2021/6/21 17:21
     * 跳过登录验证
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PassToken {
        boolean required() default true;
    }
    
    
    package cn.soboys.core.authentication;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @author kenx
     * @version 1.0
     * @date 2021/6/21 17:22
     * 需要登录验证
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UserLoginToken {
        boolean required() default true;
    }
    
    
    1. 编写业务异常AuthenticationException

    认证失败抛出认证异常AuthenticationException

    package cn.soboys.core.authentication;
    
    import lombok.Data;
    
    /**
     * @author kenx
     * @version 1.0
     * @date 2021/6/22 13:58
     * 认证异常
     */
    @Data
    public class AuthenticationException extends RuntimeException {
    
        public AuthenticationException(String message) {
            super(message);
        }
    
    }
    
    
    1. 编写认证拦截器AuthenticationInterceptor,拦截需要认证请求
    package cn.soboys.core.authentication;
    
    import cn.hutool.extra.spring.SpringUtil;
    import cn.soboys.core.ret.ResultCode;
    import cn.soboys.mallapi.entity.User;
    import cn.soboys.mallapi.service.IUserService;
    import cn.soboys.mallapi.service.impl.UserServiceImpl;
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTVerifier;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.exceptions.JWTDecodeException;
    import com.auth0.jwt.exceptions.JWTVerificationException;
    import lombok.RequiredArgsConstructor;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Method;
    
    /**
     * @author kenx
     * @version 1.0
     * @date 2021/6/21 17:24
     * 用户验证登录拦截
     */
    
    public class AuthenticationInterceptor implements HandlerInterceptor {
        //从header中获取token
        public static final String AUTHORIZATION_TOKEN = "authorizationToken";
    
    
        private  IUserService userService= SpringUtil.getBean(UserServiceImpl.class);
    
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
            String token = httpServletRequest.getHeader(AUTHORIZATION_TOKEN);// 从 http 请求头中取出 token
            httpServletRequest.setAttribute("token", token);
            // 如果不是映射到Controller mapping方法直接通过
            if (!(object instanceof HandlerMethod)) {
                return true;
            }
            HandlerMethod handlerMethod = (HandlerMethod) object;
    
            Method method = handlerMethod.getMethod();
            //检查是否有passtoken注释,有则跳过认证
            if (method.isAnnotationPresent(PassToken.class)) {
                PassToken passToken = method.getAnnotation(PassToken.class);
                if (passToken.required()) {
                    return true;
                }
            }
            //检查有没有需要用户权限的注解
            //Annotation classLoginAnnotation = handlerMethod.getBeanType().getAnnotation(UserLoginToken.class);// 类级别的要求登录标记
            if (method.isAnnotationPresent(UserLoginToken.class) || handlerMethod.getBeanType().isAnnotationPresent(UserLoginToken.class)) {
                UserLoginToken userLoginToken =
                        method.getAnnotation(UserLoginToken.class) == null ?
                                handlerMethod.getBeanType().getAnnotation(UserLoginToken.class) : method.getAnnotation(UserLoginToken.class);
                if (userLoginToken.required()) {
                    // 执行认证
                    if (token == null) {
                        throw new AuthenticationException("无token,请重新登录");
                    }
                    // 获取 token 中的 user id
                    String userId;
                    try {
                        userId = JWT.decode(token).getAudience().get(0);
                    } catch (JWTDecodeException j) {
                        throw new AuthenticationException("非法用户");
                    }
                    User user = userService.getUserInfoById(userId);
                    if (user == null) {
                        throw new AuthenticationException("用户过期,请重新登录");
                    }
                    // 验证 token
                    JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getUserMobile())).build();
                    try {
                        jwtVerifier.verify(token);
                    } catch (JWTVerificationException e) {
                        throw new AuthenticationException("非法用户");
                    }
                    return true;
                }
            }
            return true;
        }
    }
    
    

    相关文章

      网友评论

          本文标题:个人博客开发之blog-api 项目整合JWT实现token登录

          本文链接:https://www.haomeiwen.com/subject/lwadmltx.html