Java中使用JWT实现token认证

1. 实现跳过认证(PassToken)及需要认证(UserLoginToken)的注解类

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

2. 实现获取Token类(TokenService)

@Service
public class TokenService {
    public String getToken(User user) {
        // 过期时间,5分钟
        long EXPIRE_TIME = 5*60*1000;
        // 生成过期时间
        Date expireDate = new Date(System.currentTimeMillis()+EXPIRE_TIME);
        String token = JWT.create().withAudience(user.getId())// 将 user id 保存到 token 里面
                .withExpiresAt(expireDate)// 设置过期时间
                .sign(Algorithm.HMAC256(user.getPassword()));// 以 password 作为 token 的密钥
        return token;
    }
}

3. 实现token认证类(AuthenticationInterceptor)

public class AuthenticationInterceptor implements HandlerInterceptor {
    @Autowired
    UserService userService;

    @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 中的 user id
                String userId;
                try {
                    userId = JWT.decode(token).getAudience().get(0);
                } catch (JWTDecodeException j) {
                    throw new RuntimeException("token认证名称错误,请重新登录");
                }
                User user = userService.findUserById(userId);
                if (user == null) {
                    throw new RuntimeException("用户不存在,请重新登录");
                }
                // 验证 token
                JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
                try {
                    jwtVerifier.verify(token);
                } catch (JWTVerificationException e) {
                    throw new RuntimeException("token认证密码错误或登录已过期,请重新登录");
                }
                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 {
    }
}

4. 因为需要抛出异常,实现一个全局异常捕获类()

@ControllerAdvice
public class GloablExceptionHandler {
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public Object handleException(Exception e) {
        String msg = e.getMessage();
        if (msg == null || msg.equals("")) {
            msg = "服务器出错";
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("status", 500);
        jsonObject.put("message", msg);
        return jsonObject;
    }
}

5. 添加配置类(InterceptorConfig),让所有的映射路径都进行验证

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

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

6. 实现访问类(UserController)

@RestController
@RequestMapping("/api")
public class UserController {
    @Autowired
    UserService userService;
    @Autowired
    TokenService tokenService;
    //登录
    @PostMapping("/login")
    public Object login(@RequestBody User user){
        JSONObject jsonObject=new JSONObject();
        User userForBase=userService.findUserById("user");
        if(userForBase==null){
            jsonObject.put("message","登录失败,用户不存在");
            return jsonObject;
        }else {
            if (!userForBase.getPassword().equals(user.getPassword())){
                jsonObject.put("message","登录失败,密码错误");
                return jsonObject;
            }else {
                String token = tokenService.getToken(userForBase);
                jsonObject.put("token", token);
                jsonObject.put("user", userForBase);
                return jsonObject;
            }
        }
    }

    @UserLoginToken
    @GetMapping("/getMessage")
    public Object getMessage(){
        Map<String, Object> retMap = new HashMap<>();
        retMap.put("message", "你已通过验证");
        retMap.put("status", 200);
        return retMap;
    }
}

7. 进行postman访问

* http://127.0.0.1:8080/api/login

* http://127.0.0.1:8080/api/getMessage

没登录之前访问效果

登录成功

登录成功带token访问

token错误或登录时间过期后访问

github项目源码地址

https://github.com/kenyonlover/spring_boot_jwt_test
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JWT的verify方法用于验证一个JWT令牌的合法性。在JavaEE环境下,可以使用jjwtjava-jwt的相应方法进行验证。 使用jjwt库时,可以通过调用Jwts.parser().setSigningKey()方法设置签名密钥,并使用parseClaimsJws()方法解析JWT令牌。如果解析成功且验证通过,即可确定JWT令牌是合法的。例如,以下是使用jjwt库进行JWT验证的示例代码: ``` import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureException; public class JWTUtils { private static final String SECRET_KEY = "your-secret-key"; public static boolean verifyToken(String token) { try { Claims claims = Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); // 验证通过,返回true return true; } catch (SignatureException e) { // 验证失败,返回false return false; } } } ``` 使用java-jwt库时,可以通过调用JwtVerifier.verify()方法验证JWT令牌。如果验证成功,即可确定JWT令牌是合法的。例如,以下是使用java-jwt库进行JWT验证的示例代码: ``` import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; public class JWTUtils { private static final String SECRET_KEY = "your-secret-key"; public static boolean verifyToken(String token) { try { Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY); JWTVerifier verifier = JWT.require(algorithm) .build(); verifier.verify(token); // 验证通过,返回true return true; } catch (JWTVerificationException e) { // 验证失败,返回false return false; } } } ``` 以上代码的"your-secret-key"应替换为您自己的秘钥。调用verifyToken()方法并传入JWT令牌,即可验证JWT的合法性。如果验证通过,返回true;否则,返回false。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值