1. 程式人生 > 程式設計 >SpringBoot整合JWT生成token及校驗方法過程解析

SpringBoot整合JWT生成token及校驗方法過程解析

GitHub原始碼地址:https://github.com/zeng-xian-guo/springboot_jwt_token.git

封裝JTW生成token和校驗方法

public class JwtTokenUtil {

  //公用金鑰-儲存在服務端,客戶端是不會知道金鑰的,以防被攻擊
  public static String SECRET = "ThisIsASecret";

  //生成Troke
  public static String createToken(String username) {
    //簽發時間
    //Date iatDate = new Date();
    //過地時間 1分鐘後過期
    //Calendar nowTime = Calendar.getInstance();
    //nowTime.add(Calendar.MINUTE,1);
    //Date expiresDate = nowTime.getTime();
    Map<String,Object> map = new HashMap();
    map.put("alg","HS256");
    map.put("typ","JWT");
    String token = JWT.create()
          .withHeader(map)
          //.withClaim( "name","Free碼生") //設定 載荷 Payload
          //.withClaim("age","12")
          //.withClaim( "org","測試")
          //.withExpiresAt(expiresDate)//設定過期時間,過期時間要大於簽發時間
          //.withIssuedAt(iatDate)//設定簽發時間
          .withAudience(username) //設定 載荷 簽名的觀眾
          .sign(Algorithm.HMAC256(SECRET));//加密
    System.out.println("後臺生成token:" + token);
    return token;
  }

  //校驗TOKEN
  public static boolean verifyToken(String token) throws UnsupportedEncodingException{
    JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
    try {
      verifier.verify(token);
      return true;
    } catch (Exception e){
      return false;
    }
  }

  //獲取Token資訊
  public static DecodedJWT getTokenInfo(String token) throws UnsupportedEncodingException{
    JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
    try{
      return verifier.verify(token);
    } catch(Exception e){
      throw new RuntimeException(e);
    }
  }

}

新建自定義註解:@UserLoginToken

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

關於攔截器配置:

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(authenticationInterceptor())
        .addPathPatterns("/**");  // 攔截所有請求,通過判斷是否有 @LoginRequired 註解 決定是否需要登入
  }
  @Bean
  public AuthenticationInterceptor authenticationInterceptor() {
    return new 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,請重新登入");
        }
        // 驗證 token
        if(JwtTokenUtil.verifyToken(token)){
          return true;
        }else {
          throw new RuntimeException("401");
        }
      }
    }
    return true;
  }
  @Override
  public void postHandle(HttpServletRequest httpServletRequest,Object o,ModelAndView modelAndView) throws Exception {
  }
  @Override
  public void afterCompletion(HttpServletRequest httpServletRequest,Exception e) throws Exception {
  }
}

登入:

在Controller上登入方法不用新增@UserLoginToken自定義註解,其餘獲取後臺資料方法加上@UserLoginToken自定義註解,目的驗證token是否有效,是則返回資料,否則提示401無許可權。

測試:

@Controller
@RequestMapping(path = "/api")
public class IndexController {

  private String prefix = "index/";

  @GetMapping("/index")
  public String index()
  {
    return prefix + "index";
  }

  @UserLoginToken
  @PostMapping("/test")
  @ResponseBody
  public Object test(){
    Map<String,Object> map = new HashMap<>();
    map.put("code","200");
    map.put("message","你已通過驗證了");
    return map;
  }
}

HTTP請求帶上登陸成功後生成token,返回成功:

SpringBoot整合JWT生成token及校驗方法過程解析

HTTP請求帶上無效token或不帶token,返回失敗:

SpringBoot整合JWT生成token及校驗方法過程解析

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。