JWT(JJWT)结合注解实现Token验证

使用JJWT工具,实现Token验证

依赖

在SpringBoot的依赖文件中,首先导入JJWT的依赖

<dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
</dependency>

JwtTokenUtils

创建一个工具类,实现Jwt的主要功能

1、创建Token

在jwt中有三部分结构,表头、声明、加密算法

在JwtBuilder提供了在JWT规范中定义的标准注册权利要求名方便setter方法。他们是:

  • setIssuer:设置iss(发行方)索赔
  • setSubject:设置sub(主题)声明
  • setAudience:设置aud(受众群体)声明
  • setExpiration:设置exp(到期时间)声明
  • setNotBefore:设置nbf(不早于)声明
  • setIssuedAt:设置iat(签发)声明
  • setId:设置jti(JWT ID)声明
public String createJWTToken(Map<String,String> infoMap, long efftice_min_time) {
          String jwtKey = "dsgsgcxvcx54s31gd3s2x3zvdsdev";

        //The JWT signature algorithm we will be using to sign the token
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        //We will sign our JWT with our ApiKey secret
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(jwtKey);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
      
        Map<String, Object> claims = new HashMap<>(infoMap);
        UUID uuid = UUID.randomUUID();
        claims.put(Claims.ID,uuid);
        //Let's set the JWT Claims
        JwtBuilder builder = Jwts.builder()
                .setClaims(claims)
                .setExpiration(tokenExpiration)
                .signWith(signatureAlgorithm, signingKey);

        // if(null != tokenExpiration) {
        //     builder.setExpiration(tokenExpiration);
        // }

        //Builds the JWT and serializes it to a compact, URL-safe string
        return builder.compact();
    }

1、验证Token

 public static void verify(String token) {
        Jwts.parser()
                    .setSigningKey(DatatypeConverter.parseBase64Binary(jwtKey))
                    .setAllowedClockSkewSeconds(10)
                    .parseClaimsJws(token)
                    .getBody();
    }

根据代码中出现的异常,判断token状态。可能出现的异常:

  • SignatureVerificationException
  • TokenExpiredException
  • AlgorithmMismatchException
  • Exception

编写注释

用来标记 不用验证token的方法

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

用来标记 需要验证token的方法

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {


    boolean required() default true;
}

编写 拦截器

用来拦截收到的请求,判断是否需要对token进行验证。

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String token = request.getHeader("token");

        // 如果不是映射到方法,直接通过
        if (! (handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        //检查是否有 pass token 注释,如果有则跳过认真
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passTokenAnnotation = method.getAnnotation(PassToken.class);
            if (passTokenAnnotation.required()) {
                System.out.println("pass token");
                return true;
            }
        }

        // 检查是否有需要 用户权限 的注解
        if (method.isAnnotationPresent(UserLoginToken.class)) {
            UserLoginToken userLoginTokenAnnotation = method.getAnnotation(UserLoginToken.class);
            if (userLoginTokenAnnotation.required()) {

                if (token == null) {
                    throw new RuntimeException("no token info.");
                }
                // 只是简单打印结果,未做其他处理。## 
                String resToken = tokenUtils.verifyTokenDate(token);
                System.out.println("user login token :\n");
                System.out.println(resToken);

                return true;
            }
            return true;
        }

        return true;
    }

配置 拦截器

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

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**");
    }

测试

    @PassToken
    @GetMapping("/login")
    public String login() {
        TokenUtils tokenUtils = new TokenUtils();
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("id", "11111111");

        Date date = new Date();
        Date afterDate = new Date(date.getTime() + 20000);

        String jwtToken = tokenUtils.createJWTToken(paramMap, afterDate);

        return jwtToken;

    }

    @GetMapping("/test")
    @UserLoginToken
    public void testToken(@PathParam("token") String token) {
        tokenUtils.verifyTokenDate(token);
    }

讨论

关于token的时效性问题,需要考虑重置 过期时间 的问题,查看了网上的一些方法,对这个问题的处理都绝不不是很完美…


参考文档1

参考文档2

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用 Spring Boot、JWT 和拦截器实现登录验证的示例代码: 1. 添加 JWT 依赖 在 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.2</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> ``` 2. 创建 JWT 工具类 ```java import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import org.springframework.stereotype.Component; import java.security.Key; import java.util.Date; import java.util.HashMap; import java.util.Map; @Component public class JwtUtil { private final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256); public String generateToken(String subject) { return Jwts.builder() .setClaims(new HashMap<>()) .setSubject(subject) .setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 1000)) .signWith(key) .compact(); } public boolean validateToken(String token) { try { Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); return true; } catch (Exception e) { return false; } } public String getUsernameFromToken(String token) { Claims claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody(); return claims.getSubject(); } } ``` 3. 创建拦截器 ```java import com.example.demo.jwt.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; @Component public class AuthenticationInterceptor implements HandlerInterceptor { @Autowired private JwtUtil jwtUtil; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (token != null && jwtUtil.validateToken(token)) { String username = jwtUtil.getUsernameFromToken(token); request.setAttribute("username", username); return true; } else { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); LoginRequired loginRequired = method.getAnnotation(LoginRequired.class); if (loginRequired != null && modelAndView != null) { modelAndView.addObject("username", request.getAttribute("username")); } } } ``` 4. 创建注解 ```java import java.lang.annotation.*; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface LoginRequired { } ``` 5. 创建控制器 ```java import com.example.demo.interceptor.LoginRequired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/") public String index() { return "Hello World"; } @GetMapping("/hello") @LoginRequired public String hello() { return "Hello " + SecurityContextHolder.getContext().getAuthentication().getName(); } } ``` 6. 配置拦截器 ```java import com.example.demo.interceptor.AuthenticationInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private AuthenticationInterceptor authenticationInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authenticationInterceptor).addPathPatterns("/**"); } } ``` 7. 创建登录控制器 ```java import com.example.demo.jwt.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController public class LoginController { @Autowired private JwtUtil jwtUtil; @PostMapping("/login") public Map<String, Object> login(@RequestBody Map<String, String> params) { String username = params.get("username"); String password = params.get("password"); // TODO: 验证用户名和密码 String token = jwtUtil.generateToken(username); Map<String, Object> result = new HashMap<>(); result.put("token", token); return result; } } ``` 在这个示例中,我们创建了一个 JWT 工具类来生成和验证 JWT,创建了一个拦截器来验证用户是否登录,并使用 @LoginRequired 注解来标记需要登录验证的方法。我们还创建了一个登录控制器来生成 JWT。通过这个示例,您可以了解如何使用 Spring Boot、JWT 和拦截器实现登录验证

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值