很多后端开发者喜欢使用session验证,其实除了session,常见的验证方式还有cookie、三方auth接口、JWTtoken。下面将介绍JAVA中如何使用JWTtoken进行身份验证。
Jwt
全称是:json web token
。它将用户信息加密到token
里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token
的正确性,只要正确即通过验证。
URL
、POST
参数或者在HTTP header
发送,因为数据量小,传输速度也很快;Token
是以JSON
加密的形式保存在客户端的,所以JWT
是跨语言的,原则上任何web
形式都支持;一个token
分3部分,按顺序为
header
)payload
)signature
)三部分之间用.
号做分隔。例如:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxYzdiY2IzMS02ODFlLTRlZGYtYmU3Yy0wOTlkODAzM2VkY2UiLCJleHAiOjE1Njk3Mjc4OTF9.wweMzyB3tSQK34Jmez36MmC5xpUh15Ni3vOV_SGCzJ8
Jwt
的头部承载两部分信息:
Jwt
HMAC SHA256
Jwt
里验证和签名使用的算法列表如下:
JWS算法名称
载荷就是存放有效信息的地方。基本上填2
种类型数据
由这2部分内部做base64
加密。
iss: jwt签发者 sub: jwt所面向的用户 aud: 接收jwt的一方 exp: jwt的过期时间,这个过期时间必须要大于签发时间 nbf: 定义在什么时间之前,该jwt都是不可用的. iat: jwt的签发时间 jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
token
中存放的key-value
值Jwt
的第三部分是一个签证信息,这个签证信息由三部分组成
base64
加密后的header
和base64
加密后的payload
连接组成的字符串,然后通过header
中声明的加密方式进行加盐secret
组合加密,然后就构成了Jwt
的第三部分。
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version> </dependency>
//需要登录才能进行操作的注解LoginToken @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface LoginToken { boolean required() default true; } //用来跳过验证的PassToken @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface PassToken { boolean required() default true; }
@Data @AllArgsConstructor @NoArgsConstructor public class User { private String userID; private String userName; private String passWord; } package com.sky.springbootdemo.jwt.service; import com.sky.springbootdemo.jwt.entity.User; import org.springframework.stereotype.Service; /** * @title: UserService * @Author gjt * @Date: 2020-12-21 * @Description: */ @Service public class UserService { public User getUser(String userid, String password){ if ("admin".equals(userid) && "admin".equals(password)){ User user=new User(); user.setUserID("admin"); user.setUserName("admin"); user.setPassWord("admin"); return user; } else{ return null; } } public User getUser(String userid){ if ("admin".equals(userid)){ User user=new User(); user.setUserID("admin"); user.setUserName("admin"); user.setPassWord("admin"); return user; } else{ return null; } } }
package com.sky.springbootdemo.jwt.service; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.sky.springbootdemo.jwt.entity.User; import org.springframework.stereotype.Service; import java.util.Date; /** * @title: TokenService * @Author gjt * @Date: 2020-12-21 * @Description: */ @Service public class TokenService { /** * 过期时间5分钟 */ private static final long EXPIRE_TIME = 5 * 60 * 1000; public String getToken(User user) { Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); String token=""; token= JWT.create().withAudience(user.getUserID()) // 将 user id 保存到 token 里面 .withExpiresAt(date) //五分钟后token过期 .sign(Algorithm.HMAC256(user.getPassWord())); // 以 password 作为 token 的密钥 return token; } }
package com.sky.springbootdemo.jwt.interceptor; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.exceptions.JWTVerificationException; import com.sky.springbootdemo.jwt.annotation.LoginToken; import com.sky.springbootdemo.jwt.annotation.PassToken; import com.sky.springbootdemo.jwt.entity.User; import com.sky.springbootdemo.jwt.service.UserService; import org.springframework.beans.factory.annotation.Autowired; 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; /** * @title: JwtInterceptor * @Author gjt * @Date: 2020-12-21 * @Description: */ public class JwtInterceptor implements HandlerInterceptor{ @Autowired private 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(LoginToken.class)) { LoginToken loginToken = method.getAnnotation(LoginToken.class); if (loginToken.required()) { // 执行认证 if (token == null) { throw new RuntimeException("无token,请重新登录"); } // 获取 token 中的 user id String userId; try { userId = JWT.decode(token).getAudience().get(0); } catch (JWTDecodeException j) { throw new RuntimeException("401"); } User user = userService.getUser(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("401"); } 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 { } }
package com.sky.springbootdemo.jwt.config; import com.sky.springbootdemo.jwt.interceptor.JwtInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @title: InterceptorConfig * @Author gjt * @Date: 2020-12-21 * @Description: */ @Configuration public class InterceptorConfig implements WebMvcConfigurer{ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor()) .addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录 //注册TestInterceptor拦截器 // InterceptorRegistration registration = registry.addInterceptor(jwtInterceptor()); // registration.addPathPatterns("/**"); //添加拦截路径 // registration.excludePathPatterns( //添加不拦截路径 // "/**/*.html", //html静态资源 // "/**/*.js", //js静态资源 // "/**/*.css", //css静态资源 // "/**/*.woff", // "/**/*.ttf", // "/swagger-ui.html" // ); } @Bean public JwtInterceptor jwtInterceptor() { return new JwtInterceptor(); } }
package com.sky.springbootdemo.jwt.controller; import com.alibaba.fastjson.JSONObject; import com.sky.springbootdemo.jwt.annotation.LoginToken; import com.sky.springbootdemo.jwt.entity.User; import com.sky.springbootdemo.jwt.service.TokenService; import com.sky.springbootdemo.jwt.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; /** * @title: Login * @Author gjt * @Date: 2020-12-22 * @Description: */ @RestController public class Login { @Autowired private UserService userService; @Autowired private TokenService tokenService; @PostMapping("login") public Object login(String username, String password){ JSONObject jsonObject=new JSONObject(); User user=userService.getUser(username, password); if(user==null){ jsonObject.put("message","登录失败!"); return jsonObject; }else { String token = tokenService.getToken(user); jsonObject.put("token", token); jsonObject.put("user", user); return jsonObject; } } @LoginToken @PostMapping("/getMessage") public String getMessage(){ return "你已通过验证"; } }
package com.sky.springbootdemo.jwt.controller; import com.alibaba.fastjson.JSONObject; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * @title: GlobalExceptionHandler * @Author gjt * @Date: 2020-12-22 * @Description: */ @RestControllerAdvice public class GlobalExceptionHandler { @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("code", 1000); jsonObject.put("message", msg); return jsonObject; } }
3.1、获取tockem
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:
https://blog.csdn.net/gjtao1130/article/details/111658060
相关文章
很多后端开发者喜欢使用session验证,其实除了session,常见的验证方式还有cookie、三方auth接口、JWTtoken。下面将
FlashFXP绿色版网盘下载,附激活教程 1929
FlashFxp百度网盘下载链接:https://pan.baidu.com/s/1MBQ5gkZY1TCFY8A7fnZCfQ。FlashFxp是功能强大的FTP工具
Adobe Fireworks CS6 Ansifa绿色精简版网盘下载 1669
firework可以制作精美或是可以闪瞎眼的gif,这在广告领域是需要常用的,还有firework制作下logo,一些原创的图片还是很便捷的,而且fireworks用法简单,配合dw在做网站这一块往往会发挥出很强大的效果。百度网盘下载链接:https://pan.baidu.com/s/1fzIZszfy8VX6VzQBM_bdZQ
navicat for mysql中文绿色版网盘下载 1702
Navicat for Mysql是用于Mysql数据库管理的一款图形化管理软件,非常的便捷和好用,可以方便的增删改查数据库、数据表、字段、支持mysql命令,视图等等。百度网盘下载链接:https://pan.baidu.com/s/1T_tlgxzdQLtDr9TzptoWQw 提取码:y2yq
火车头采集器(旗舰版)绿色版网盘下载 1796
火车头采集器是站长常用的工具,相比于八爪鱼,简洁好用,易于配置。火车头能够轻松的抓取网页内容,并通过自带的工具对内容进行处理。站长圈想要做网站,火车头采集器是必不可少的。百度网盘链接:https://pan.baidu.com/s/1u8wUqS901HgOmucMBBOvEA
Photoshop(CS-2015-2023)绿色中文版软件下载 1919
安装文件清单(共46G)包含Window和Mac OS各个版本的安装包,从cs到cc,从绿色版到破解版,从安装文件激活工具,应有尽有,一次性打包。 Photoshop CC绿色精简版 Photoshop CS6 Mac版 Photoshop CC 2015 32位 Photoshop CC 2015 64位 Photoshop CC 2015 MAC版 Photoshop CC 2017 64位 Adobe Photoshop CC 2018 Adobe_Photoshop_CC_2018 Photoshop CC 2018 Win32 Photoshop CC 2018 Win64