SpringBoot整合JWT(二)
JWT相关概念介绍:
1、头部信息
2、载荷信息
3、签名信息
一、头部信息:头部信息由两部分组成1、令牌的类型,即JWT;2、使用的签名算法,例如HMASSHA256或RSA;
头部信息JSON代码如下:然后这个JSON被编码为Base64URL,形成JWT的第一部分
{"alg": "HS256","typ": "JWT"
}
二、载荷信息:其中包含声明(claims),声明可以存放实体和其它数据的声明,声明包括三种类型
1、已注册声明:这些是一组预定义声明,不是强制性的,但建议使用,以提供一组有用的,可互操作的声明。其中一些是:** iss(发行人), exp(到期时间),sub(主题), aud**(观众)等
2、公开声明:可以参考 IANA JSON Web令牌注册表https://www.iana.org/assignments/jwt/jwt.xhtml) 查看公共的声明
3、私有声明:根据自己的业务需要自定义一些数据格式,示例如下
{"sub": "1234567890","name": "John Doe","admin": true}
三、签名信息:这个部分需要 base64 加密后的 头部信息(header) 和 base64 加密后的载荷信息(payload),使用连接组成的字符串,然后通过头部信息(header)中声明的加密方式进行加盐 secret 组合在加密,然后就构成了 JWT 的第三部分。
例如,如果要使用HMAC SHA256算法,将按以下方式创建签名:
HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
通过三种方法演示如何使用JWT
1、创建不携带自定义信息的token,方法createToken() ;
2、创建携带自定义信息的token,方法createTokenWithClaim();
3、创建携带自定义信息的token,并使用Base64再次处理,方法createTokenWithClaimWithBase();
3、验证token信息并解析token中的内容,方法verifyToken()
说明:JWT在生成Token的时候,如果需要自定义信息,会使用到.withClaim();如果不需要自定义,则不需要,下面代码都有详细注释说明。注意使用Gson需要引入对应依赖,依赖如下
<!-- gson -->
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.5</version>
</dependency>
一、自定义两个注解,分别用于token验证和跳过token验证
1、自定义注解PassToken,用于跳过Token验证
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 用来跳过验证的注解*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {boolean required() default true;}
2、自定义注解UserLoginToken,用于Token验证
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 需要登录才能进行操作的注解*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {boolean required() default true;}
二、书写JWT方法,包括生成token和解密token
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.dream.fly.readbook.entity.User;
import com.google.common.io.BaseEncoding;
import com.google.gson.Gson;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 生成token的方法*/
public class JWTUtil {/*** 设置过期时间(一天)*/
// private static final long EXPIRE_TIME = 24*60*60*1000;private static final long EXPIRE_TIME = 60*1000;/*** 设置token私钥*/private static final String TOKEN_SECRET = "one_smile";/*** 创建不携带自定义信息的token*/public static String createToken(User user){//构建头部信息Map<String,Object> map = new HashMap<String,Object>();map.put("alg","HS256");map.put("typ","JWT");//构建密钥信息。使用自定义token密钥还是用户密码都可以,选择不一样,在解密的时候会不一样。一般建议自定义,安全、方便Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); //使用自定义的token密钥
// Algorithm algorithm = Algorithm.HMAC256(user.getRead_userpass()); //使用用户输入的用户密码作为密钥//通过定义注册并组合头部信息和密钥信息生成jwt tokenDate nowDate = new Date();Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME); //过期时间预处理String token = JWT.create().withHeader(map) //设置头部信息Header.withIssuer("SERVICE") //设置 载荷 签名是有谁生成 例如 服务器.withSubject("this is readbook token") //设置 载荷 签名的主题
// .withNotBefore(new Date()) //设置 载荷 定义在什么时间之前,该jwt都是不可用的..withAudience(user.getRead_username()) //设置 载荷 签名的观众 也可以理解谁接受签名的.withIssuedAt(nowDate) //设置 载荷 生成签名的时间.withExpiresAt(expireDate) //设置 载荷 签名过期的时间.sign(algorithm); //签名 Signaturereturn token;}/*** 创建携带自定义信息和声明并存的的jwt token*/public static String createTokenWithClaim(User user){//构建头部信息Map<String,Object> map = new HashMap<>();map.put("typ","JWT");map.put("alg","HS256");//构建密钥信息。使用自定义token密钥还是用户密码都可以,选择不一样,在解密的时候会不一样。一般建议自定义,安全、方便Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); //使用自定义的token密钥
// Algorithm algorithm = Algorithm.HMAC256(user.getRead_userpass()); //使用用户输入的用户密码作为密钥//通过自定义声明并组合头部细腻些和密钥信息生成jwt tokenDate nowDate = new Date();Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME); //过期时间预处理String token = JWT.create().withHeader(map).withClaim("loginName",user.getRead_username()) //自定义,登录用户名.withClaim("deptName","技术部") //自定义,部门.withClaim("loginPass",user.getRead_userpass()) //自定义,登录用户密码.withIssuer("SERVICE") // 声明,签名是有谁生成 例如 服务器.withSubject("this is test token") //声明, 签名的主题// .withNotBefore(new Date()) //声明,定义在什么时间之前,该jwt都是不可用的.withAudience("APP") //声明, 签名的观众 也可以理解谁接受签名的.withIssuedAt(nowDate) //声明, 生成签名的时间.withExpiresAt(expireDate)//声明, 签名过期的时间.sign(algorithm); //签名signaturereturn token;}/*** 创建携带自定义信息和声明并存的的jwt token* 同时使用base64进一步加密*/public static String createTokenWithClaimWithBase(User user){//构建头部信息Map<String,Object> map = new HashMap<>();map.put("typ","JWT");map.put("alg","HS256");Gson gson = new Gson();String userJson = gson.toJson(user);String userJsonBase64 = BaseEncoding.base64().encode(userJson.getBytes());//构建密钥信息Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);//通过自定义声明并组合头部细腻些和密钥信息生成jwt tokenDate nowDate = new Date();Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME); //过期时间预处理String token = JWT.create().withClaim("user",userJsonBase64).withIssuer("SERVICE")// 签名是有谁生成.withSubject("this is test token")// 签名的主题// .withNotBefore(new Date())//该jwt都是不可用的时间.withAudience("APP")// 签名的观众 也可以理解谁接受签名的.withIssuedAt(nowDate) // 生成签名的时间.withExpiresAt(expireDate)// 签名过期的时间.sign(algorithm);//签名 Signaturereturn token;}/*** 验证jwt token* 如果在生成token的步奏中构建密钥信息使用了用户密码,则在解密的时候,同样构建密钥信息的时候需要用户密码*/public static void verifyToken(String token){//构建密钥信息Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);//通过密钥信息和签名的发布者的信息生成JWTVerifier(JWT验证类)。不提那家发布者的信息也可以获取JWTVerifierJWTVerifier verifier = JWT.require(algorithm)
// .withIssuer("SERVICE") //不添加.withIssuer("SERVICE") 也可以获取JWTVerifier.build();//通过JWTVerifier获取token中的信息DecodedJWT jwt = verifier.verify(token);//获取token中的声明和自定义声明String subject = jwt.getSubject();List<String> audience = jwt.getAudience();Map<String, Claim> claims = jwt.getClaims();for (Map.Entry<String, Claim> entry : claims.entrySet()){String key = entry.getKey();Claim claim = entry.getValue();String value = claim.asString();System.out.println("key:"+key+" value:"+claim.asString());}}}
三、书写拦截器,定义拦截规则
import com.dream.fly.readbook.CustomAnno.PassToken;
import com.dream.fly.readbook.CustomAnno.UserLoginToken;
import com.dream.fly.readbook.service.ProjectService;
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;/*** 拦截器* 获取token并验证token*/
public class JWTAuthenticationInterceptor implements HandlerInterceptor {@Autowiredprivate ProjectService projectService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("token"); //从http请求头中取出token//如果不是映射到方法就直接通过if(!(handler instanceof HandlerMethod)){return true;}HandlerMethod handlerMethod = (HandlerMethod) handler;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,请重新登录!");}//调用JWT解密方法,可以在解密方法中定义返回数据,这里可以继续根据返回值进行判断,也可以在解密方法中判断,具体自行定义JWTUtil.verifyToken(token);}}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
四、定义配置文件,将拦截器配置进系统,使其生效
import com.dream.fly.readbook.utils.JWTAuthenticationInterceptor;
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;@Configuration
public class JWTInterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtAuthenticationInterceptor()).addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录}@Beanpublic JWTAuthenticationInterceptor jwtAuthenticationInterceptor(){return new JWTAuthenticationInterceptor();}
}
五、项目接口中使用
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dream.fly.readbook.CustomAnno.UserLoginToken;
import com.dream.fly.readbook.entity.User;
import com.dream.fly.readbook.service.ProjectService;
import com.dream.fly.readbook.utils.JWTUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;/*** 项目初始化相关配置* 例如:* 1、首页*/
@RestController
@Api(tags = "项目初始化接口")
public class ProjectCotroller {@Autowiredprivate ProjectService projectService;/*** 用户登录* @param username 用户名* @param passwd 密码* @return*/@PostMapping("/userLogin")@ApiOperation(value = "用户登录",notes = "用户登录")@ApiImplicitParams({@ApiImplicitParam(name = "username",value = "登录账号",required = true,paramType = "query"),@ApiImplicitParam(name = "passwd",value = "登录密码",required = true,paramType = "query")})public JSONObject userLogin(String username,String passwd){Boolean loginInfo = this.projectService.userLogin(username, passwd);Map map = new HashMap();map.put("loginInfo",loginInfo);if (loginInfo){ //如果登录成功需要把token带给前端User user = new User();user.setRead_username(username);user.setRead_userpass(passwd);//调用JWT生成Token方法,使其登录接口就生成token,返回给前端,便于后续接口使用String token = JWTUtil.createTokenWithClaimWithBase(user);map.put("token",token);}JSONObject jsonObject = new JSONObject(map);return jsonObject;}@UserLoginToken@GetMapping("/getMessage")public String getMessage(){System.out.println("进入方法");return "你已经通过验证";}}
SpringBoot整合JWT(二)相关推荐
- springboot整合jwt
JWT(Json Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准.JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取 ...
- SpringBoot 整合JWT实现基于自定义注解的-登录请求验证拦截(保姆级教学,附:源码)
学习目标: Spring Boot 整合JWT实现基于自定义注解的 登录请求接口拦截 例: 一篇掌握 JWT 入门知识 1.1 在学习SpringBoot 整合JWT之前,我们先来说说JWT进行用户 ...
- SpringBoot整合JWT实现登录认证
目录 什么是JWT 为什么使用JWT JWT的使用场景 JWT的结构 JWT的请求流程 SpringBoot整合JWT 引入依赖 编写配置文件 token生成与验证工具类 拦截器拦截token 设置拦 ...
- 三分钟springboot整合dubbo3(二)(Triple协议流式调用)
三分钟springboot整合dubbo3(二)(Triple协议与流式调用) 1.Triple协议(粘贴官网) 2.流式调用绍 3.使用方式 新增依赖 配置文件 代码演示 3.1.ServerStr ...
- 教你 Shiro + SpringBoot 整合 JWT
本篇文章将教大家在 shiro + springBoot 的基础上整合 JWT (JSON Web Token) 如果对 shiro 如何整合 springBoot 还不了解的可以先去看我的上一篇文章 ...
- SpringBoot整合JWT实现API身份校验
上一个项目采用的是session存储uid的方式来确认API调用方的合法身份,这次的app则打算采用token的方式进行身份校验,此二者的优缺点有很多博客进行了论述,这里就不谈了. 本文中的代码以及部 ...
- SpringBoot 整合 JWT 实现 Token 验证
前言 在Spring Security整合oauth2实现认证token也不满足实际生产需求的时候,可以整合Jwt实现token认证,完全手写获取token,认证token的方法. Maven依赖包 ...
- springboot整合jwt与vue的后端管理系统1
该项目使用技术springboot.security.redis.mybatis-plus 第一步:在idea中新建一个springboot项目,在pom.xml文件导入相应的依赖jar <de ...
- springboot整合微信二维码支付
微信支付官方文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/api.shtml 下图是微信支付的一个流程图: 我们需要做的是: 1.调用 ...
- JWT,springboot整合JWT完成token的验证,token的使用,java架构师技术栈
/** @author dugt1998@163.com @date 2020/11/8 12:40 */ public class JWTUtils { //签名 自己项目中的签名 private ...
最新文章
- StaticLayout的介绍/使用
- C++ algorithm中find系列函数总结
- 【数字信号处理】傅里叶变换性质 ( 傅里叶变换时移性质示例 )
- 笔记 - AliCloud Auto Scaling(弹性伸缩)简介
- 前端月趋势榜:5 月最热门的 20 个前端开源项目 - 2105
- Python基础之基本数据类型的总结
- vue中mixins的使用方法和注意地方
- C++工作笔记-hiredis中关于ERR wrong number of arguments for HMSET问题的解决
- 鲲鹏性能优化十板斧(四)——磁盘IO子系统性能调优
- Android修改kernel logo和开机动画(android)
- 网站被挂黑链是什么原因,如何解决挂黑链问题!
- 【Redis踩坑日记】Redis由于目标计算机积极拒绝,无法连接
- 用java做打字训练测试软件,《打字训练测试软件-Java课程设计》.doc
- 华硕关闭更新BIOS
- 如何搭建App自动化测试框架?
- 正片工艺、负片工艺,这两种PCB生产工艺的差异到底是什么?
- 商业模式是利益相关者的交易结构
- PageHelper这种情况下有坑!注意别吃亏
- C++编译报错: undefined reference to clock_gettime
- C语言程序设计课程设计——三国杀游戏
热门文章
- WGS84 与 北京54 坐标系互转
- python numpy log_工具amp;方法 | 6行代码教你用Python做OLS回归(内附CFPS实例)
- 睿智的目标检测26——Pytorch搭建yolo3目标检测平台
- steam错误代码 -118 ; 443/80或其他端口被占用,请关闭占用该端口的进程后再点击启动服务 ; 关闭端口进程
- c语言输出100以内的素数存放数组中,c语言素数(c语言输出100以内素数)
- matlab中进行多行注释
- 全卷积 FCN 数据标签制作
- Python—爬取全国城市名称案例(Xpath方法)
- Android Wi-Fi subsystem_ramdump简介(以QCOM为Base)
- matlab中simulink文件批量修改版本