小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

json-web-token(JWT)

 貪挽懶月 2022-06-20 發(fā)布于廣東
JWT是什么


JWT的全稱為json web token。不要把它想得多么高深,其實(shí)就是一種生成token的方式。一般我們訪問一個系統(tǒng)的流程就是:請求登錄接口,該接口會返回一個token,請求其他接口都要帶上token,token驗(yàn)證通過才能訪問成功,而JWT可以理解為就是生成token的一種機(jī)制。

JWT怎么用

1、添加jwt的依賴:

<!-- JWT -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
</dependency>

2、新建一個TokenService,用來生成token:

@Service
public class TokenService {
    // token過期時間5分鐘
    private static final long EXPIRE_TIME = (60 * 1000 * 5);

    public String getToken(User user) {
        return JWT.create()
                // 需要放入token中的信息
                .withAudience(user.getId())
                // 設(shè)置token過期時間
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRE_TIME))
                // 用戶密碼當(dāng)作密鑰
                .sign(Algorithm.HMAC256(user.getPassword()));
    }
}

User類就是一個普通的pojo,這里就不把代碼貼出來了。這個getToken方法表示將用戶的密碼作為密鑰,把用戶的id放進(jìn)token中,設(shè)置token過期時間為5分鐘。

3、新建兩個注解,一個注解表示需要驗(yàn)證,另一個表示跳過驗(yàn)證:

  • 需要驗(yàn)證:

//可以作用在方法,類和接口上
@Target({ElementType.METHOD, ElementType.TYPE})
//編譯器會將SkipToken的信息保存在虛擬機(jī)中
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedToken {
    // required 屬性默認(rèn)值為true
    boolean required() default true;
}
  • 跳過驗(yàn)證:

@Target({ElementType.METHODElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SkipToken {
    boolean required() default true;
}

4、新建一個AuthInterceptor類,用于攔截請求:

public class AuthInterceptor implements HandlerInterceptor {
    @Autowired
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,Object object) {
        // 從 http 請求頭中取出 token
        String token = httpServletRequest.getHeader("token");
        // 只攔截方法,不是方法直接返回true
        if (!(object instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) object;
        Method method = handlerMethod.getMethod();
        // 有SkipToken注解的直接跳過認(rèn)證
        if (method.isAnnotationPresent(SkipToken.class)) {
            SkipToken skipToken = method.getAnnotation(SkipToken.class);
            if (skipToken.required()) {
                return true;
            }
        }
        // 有NeedToken注解的就進(jìn)行認(rèn)證
        if (method.isAnnotationPresent(NeedToken.class)) {
            NeedToken needToken = method.getAnnotation(NeedToken.class);
            if (needToken.required()) {
                if (token == null) {
                    throw new RuntimeException("無token,請重新登錄");
                }
                // 獲取 token 中的 userId
                String userId;
                try {
                    userId = JWT.decode(token).getAudience().get(0);
                } catch (JWTDecodeException j) {
                    throw new RuntimeException("401");
                }
                // 根據(jù)userId查詢數(shù)據(jù)庫
                User user = userService.findUserById(userId);
                if (user == null) {
                    throw new RuntimeException("用戶不存在,請重新登錄");
                }
                // 用查出來的user的密碼去校驗(yàn)token
                JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
                try {
                    // 沒發(fā)生異常就表示校驗(yàn)通過
                    jwtVerifier.verify(token);
                } catch (JWTVerificationException e) {
                    throw new RuntimeException("401");
                }
                return true;
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse, Object o,ModelAndView modelAndView) {
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o, Exception e) {
    }
}

這個攔截器的處理邏輯就是:

  • 只攔截方法,如果不是方法,就放行;

  • 如果攔截的方法有@SkipToken注解,放行;

  • 如果攔截的方法有@NeedToken注解,則需要驗(yàn)證token;

  • 取出請求頭中的token,拿出token中的userId,根據(jù)此userId去數(shù)據(jù)庫查詢對應(yīng)的記錄;

  • 再將查出來的user的password去驗(yàn)證token,驗(yàn)證成功則放行;

  • 如果沒有@NeedToken也沒有@SkipToken注解的,也放行。

5、新建一個InterceptorConfig類,將我們上面寫的攔截器配置到spring容器中去:

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor())
                .addPathPatterns("/**");   
    }
    @Bean
    public AuthInterceptor authInterceptor() {
        return new AuthInterceptor();
    }
}

6、在controller中的用法:

@RestController
@RequestMapping("api")
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private TokenService tokenService;

    @SkipToken
    @PostMapping("/user")
    public JsonResult login(User user){
        User dbUser = userService.findForLogin(user);
        if (dbUser == null){
            return new JsonResult(200"用戶名或密碼錯誤"null);
        } else {
            String token = tokenService.getToken(dbUser);
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("token", token);
            resultMap.put("user", dbUser);
            return new JsonResult(200"登錄成功", resultMap);
        }
    }

    @NeedToken
    @GetMapping("/getMessage")
    public String getMessage(){
        return "你已通過驗(yàn)證";
    }

    @SkipToken
    @GetMapping("/noToken")
    public String noToken() {
        return "無需token訪問";
    }
}

以上就是JWT的用法,其實(shí)在實(shí)際生產(chǎn)中一般會配合shiro使用。

-java開發(fā)那些事兒-

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多