美文网首页
SpringBoot-JWT

SpringBoot-JWT

作者: 猫啸山林 | 来源:发表于2019-11-07 16:45 被阅读0次

参考文章:https://www.jianshu.com/p/e88d3f8151db

1、添加项目依赖

implementation 'com.auth0:java-jwt:3.4.1'

2、新建JWT工具类JwtUtil

public class JwtUtil {

    // 过期时间120分钟
    public static final long EXPIRE_TIME = 120 * 60 * 1000;

    /**
     * 校验token是否正确
     *
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            // 根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
            // 效验TOKEN
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名,5min后过期
     *
     * @param username 用户名
     * @param secret   用户的密码
     * @return 加密的token
     */
    public static String sign(String username, String secret) {
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带username信息
        return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);

    }

}

3、编写Token验证拦截器

public class AuthenticationInterceptor implements HandlerInterceptor {

    @Resource
    private UserRepository userRepository;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {

        String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
        // 如果不是映射到方法直接通过
        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;
            }
        }

        //检查有没有需要用户权限的注解
        if (method.isAnnotationPresent(UserLoginToken.class)) {
            UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
            if (userLoginToken.required()) {
                // 执行认证
                if (token == null) {
                    throw new RuntimeException("无token,请重新登录");
                }
                // 获取 token 中的 user id
                String username = JwtUtil.getUsername(token);
                if (username == null) {
                    throw new RuntimeException("获取用户名失败,请重新登录");
                }
                SysUser user = userRepository.findByUsername(username);
                if (user == null) {
                    throw new RuntimeException("用户不存在,请重新登录");
                }
                // 验证 token
                return JwtUtil.verify(token, user.getUsername(), user.getPassword());
            }

        }
        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 {

    }

}

4、配置拦截器

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**");    // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
    }

    @Bean
    public AuthenticationInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }

}

5、全局异常捕捉

@ControllerAdvice
public class GloablExceptionHandler {

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public Result<String> handleException(Exception e) {
        Result<String> result = new Result<>();
        String msg = e.getMessage();
        if (msg == null || msg.equals("")) {
            msg = "服务器出错";
        }
        result.error(msg);
        return result;
    }

}

6、自定义两个注解

-跳过验证的PassToken

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
    boolean required() default true;
}

-登录才能进行操作的注解UserLoginToken

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
    boolean required() default true;
}

7、用户登录UserController

@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserRepository userRepository;

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Result<String> userLogin(@RequestBody LoginModel loginModel) {
        System.out.println(loginModel.getUsername() + "/" + loginModel.getPassword());
        Result<String> result = new Result<>();
        SysUser user = userRepository.findByUsername(loginModel.getUsername());
        if (user != null && loginModel.getPassword().equals(user.getPassword())) {
            user.setLoginTime(new Date());
            userRepository.saveAndFlush(user);
            String token = JwtUtil.sign(loginModel.getUsername(), loginModel.getPassword());
            System.out.println(token);
            result.setResult(token);
            result.success("登录成功");
        } else {
            result.error("用户名或密码错误");
        }
        return result;
    }

    @UserLoginToken
    @GetMapping("/getMessage")
    public String getMessage(){
        return "你已通过验证";
    }
}

相关文章

  • SpringBoot-JWT

    参考文章:https://www.jianshu.com/p/e88d3f8151db 1、添加项目依赖 impl...

网友评论

      本文标题:SpringBoot-JWT

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