本篇和大家分享jwt(json web token)的使用,她主要用来生成接口访问的token和验证,其单独结合springboot来开发api接口token验证很是方便,由于jwt的token中存储有用户的信息并且有加密,所以适用于分布式,这样直接吧信息存储在用户本地减速了服务端存储sessiion或token的压力;如下快速使用:

 <!--jwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.</version>
</dependency>
<!--阿里 FastJson依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.</version>
</dependency>

一般使用jwt来达到3种结果:

  • 生成token
  • 验证token是否有效
  • 获取token中jwt信息(主要用户信息)

生成token

引入了jjwt依赖后,要生成token很方便;对于一个token来说,代表的是唯一并且不可逆的,因此我们在生成时需要增加一些唯一数据进去,比如下面的id:

 long currentTime = System.currentTimeMillis();
return Jwts.builder()
.setId(UUID.randomUUID().toString())
.setIssuedAt(new Date(currentTime)) //签发时间
.setSubject("system") //说明
.setIssuer("shenniu003") //签发者信息
.setAudience("custom") //接收用户
.compressWith(CompressionCodecs.GZIP) //数据压缩方式 .signWith(SignatureAlgorithm.HS256, encryKey) //加密方式
.setExpiration(new Date(currentTime + secondTimeOut * )) //过期时间戳
.addClaims(claimMaps) //cla信息
.compact();

通过uuid来标记唯一id信息;当然在对token加密时需要用到秘钥,jwt很是方便她支持了很多中加密方式如:HS256,HS265,Md5等复杂及常用的加密方式;

jwt生成的token中内容分为3个部分:head信息,payload信息,sign信息,通常我们要做的是往payload增加一些用户信息(比如:账号,昵称,权限等,但不包含密码);在对jwt的token有一定了解后,我们来看下真实生成的token值:

 eyJhbGciOiJIUzI1NiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAFWMTQ7CIBSE7_LWkPDzaEsP4QnYINCIptX4INE0vbtg4sLlfPPN7HAtGWbwg1BKL4GrcbEcIwpujZF8iiEpjXFapAAG2ReYpUEcR2VxYED13Nb0ppLW3hP1eEnblqsQuiFfY0OhUrl3I70evweU_aFSejZhd7DlcDv5NTmYHUilHTD3rf_hAccHRTv--7YAAAA.i4xwoQtaWI0-dwHWN8uZ4DBm-vfli5bavYU9lRYxU5E

验证token是否有效

token生成的时都会伴随者有一个失效的时间,在这我们可以通过setExpiration函数设置过期时间,记住jwt的有效时间不是滑动的,也就是说不做任何处理时,当到达第一次设置的失效时间时,就基本没用了,要获取token是否过期可以使用如下方式:

 public static boolean isExpiration(String token, String encryKey) {
try {
return getClaimsBody(token, encryKey)
.getExpiration()
.before(new Date());
} catch (ExpiredJwtException ex) {
return true;
}
}

这里使用了date的before来用获取的过期时间和当前时间对比,判断是否继续有效,需要注意的是如果在token失效后再通过getClaimsBody(token, encryKey)获取信息,此时会报ExpiredJwtException错误,我们即可认为过期。

获取token中jwt信息(主要用户信息)

通常我们要把登录用户信息存储在jwt生成的token中,这里可以通过 addClaims(claimMaps) 传递map来设置信息,反过来要获取token中的用户信息,我们需要这样做:

 return Jwts.parser()
.setSigningKey(encryKey)
.parseClaimsJws(token)
.getBody();

此时body获取出来是Claims类型,我们需要从中获取到用户信息,需要注意的是在addClaims存储信息的时候如果存储的map值没做过出来,那完整的实体对象存储进去后会映射成一个LinkHasMap类型,如下:

因此通常会在存储的时候json化,如下代码:

 claimMaps.forEach((key, val) -> {
claimMaps.put(key, JSON.toJSONString(val));
});

再来就是通过get方法获取我们存储进去的信息,并json反序列化:

 /**
* 获取body某个值
*
* @param token
* @param encryKey
* @param key
* @return
*/
public static Object getVal(String token, String encryKey, String key) {
return getJws(token, encryKey).getBody().get(key);
} /**
* 获取body某个值,json字符转实体
*
* @param token
* @param encryKey
* @param key
* @param tClass
* @param <T>
* @return
*/
public static <T> T getValByT(String token, String encryKey, String key, Class<T> tClass) {
try {
String strJson = getVal(token, encryKey, key).toString();
return JSON.parseObject(strJson, tClass);
} catch (Exception ex) {
return null;
}
}

来到这里一个Jwt的Util代码基本就完成了,下面给出完整的代码例子,仅供参考:

 public class JwtUtil {

     /**
* 获取token - json化 map信息
*
* @param claimMaps
* @param encryKey
* @param secondTimeOut
* @return
*/
public static String getTokenByJson(Map<String, Object> claimMaps, String encryKey, int secondTimeOut) {
return getToken(claimMaps, true, encryKey, secondTimeOut);
} /**
* 获取token
*
* @param claimMaps
* @param isJsonMpas
* @param encryKey
* @param secondTimeOut
* @return
*/
public static String getToken(Map<String, Object> claimMaps, boolean isJsonMpas, String encryKey, int secondTimeOut) { if (isJsonMpas) {
claimMaps.forEach((key, val) -> {
claimMaps.put(key, JSON.toJSONString(val));
});
}
long currentTime = System.currentTimeMillis();
return Jwts.builder()
.setId(UUID.randomUUID().toString())
.setIssuedAt(new Date(currentTime)) //签发时间
.setSubject("system") //说明
.setIssuer("shenniu003") //签发者信息
.setAudience("custom") //接收用户
.compressWith(CompressionCodecs.GZIP) //数据压缩方式 .signWith(SignatureAlgorithm.HS256, encryKey) //加密方式
.setExpiration(new Date(currentTime + secondTimeOut * )) //过期时间戳
.addClaims(claimMaps) //cla信息
.compact();
} /**
* 获取token中的claims信息
*
* @param token
* @param encryKey
* @return
*/
private static Jws<Claims> getJws(String token, String encryKey) {
return Jwts.parser()
.setSigningKey(encryKey)
.parseClaimsJws(token);
} public static String getSignature(String token, String encryKey) {
try {
return getJws(token, encryKey).getSignature();
} catch (Exception ex) {
return "";
}
} /**
* 获取token中head信息
*
* @param token
* @param encryKey
* @return
*/
public static JwsHeader getHeader(String token, String encryKey) {
try {
return getJws(token, encryKey).getHeader();
} catch (Exception ex) {
return null;
}
} /**
* 获取payload body信息
*
* @param token
* @param encryKey
* @return
*/
public static Claims getClaimsBody(String token, String encryKey) {
return getJws(token, encryKey).getBody();
} /**
* 获取body某个值
*
* @param token
* @param encryKey
* @param key
* @return
*/
public static Object getVal(String token, String encryKey, String key) {
return getJws(token, encryKey).getBody().get(key);
} /**
* 获取body某个值,json字符转实体
*
* @param token
* @param encryKey
* @param key
* @param tClass
* @param <T>
* @return
*/
public static <T> T getValByT(String token, String encryKey, String key, Class<T> tClass) {
try {
String strJson = getVal(token, encryKey, key).toString();
return JSON.parseObject(strJson, tClass);
} catch (Exception ex) {
return null;
}
} /**
* 是否过期
*
* @param token
* @param encryKey
* @return
*/
public static boolean isExpiration(String token, String encryKey) {
try {
return getClaimsBody(token, encryKey)
.getExpiration()
.before(new Date());
} catch (ExpiredJwtException ex) {
return true;
}
} public static String getSubject(String token, String encryKey) {
try {
return getClaimsBody(token, encryKey).getSubject();
} catch (Exception ex) {
return "";
}
}
}

过滤器验证token

有了基本的JwtUtil工具,我们需要用到springboot项目中,一般来说对于登录授权token验证可以通过过滤器来操作,这里创建一个AuthenFilter,用于对post请求过来的token做验证:

 public class AuthenFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest rq = (HttpServletRequest) servletRequest;
HttpServletResponse rp = (HttpServletResponse) servletResponse;
RpBase rpBase = new RpBase();
try {
//只接受post
if (!rq.getMethod().equalsIgnoreCase("post")) {
filterChain.doFilter(servletRequest, servletResponse);
return;
} String token = rq.getHeader("token");
if (StringUtils.isEmpty(token)) {
rpBase.setMsg("无token");
return;
} //jwt验证
MoUser moUser = JwtUtil.getValByT(token, WebConfig.Token_EncryKey, WebConfig.Login_User, MoUser.class);
if (moUser == null) {
rpBase.setMsg("token已失效");
return;
} System.out.println("token用户:" + moUser.getNickName()); filterChain.doFilter(servletRequest, servletResponse);
} catch (Exception ex) {
} finally {
if (!StringUtils.isEmpty(rpBase.getMsg())) {
rp.setCharacterEncoding("utf-8");
rpBase.setCode(HttpStatus.BAD_REQUEST.value());
rp.getWriter().write(JSON.toJSONString(rpBase));
}
}
}
}

要是自定义过滤器AuthenFilter生效,还需要把她注册到容器中,这里通过编码方式,当然还可以通过@WebFilter注解来加入到容器中:

 @Configuration
public class WebFilterConfig { @Bean
public FilterRegistrationBean setFilter() { FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new AuthenFilter());
registrationBean.addUrlPatterns("/api/*");
registrationBean.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); return registrationBean;
}
}

注意addUrlPatterns匹配的是过滤器作用的url连接,根据需求而定;为了验证效果,这里我创建了两个接口getToken和t0,分别是获取token和post查询接口,代码如是:

 @RestController
public class TestController { @PostMapping("/api/t0")
public String t0() throws MyException { return UUID.randomUUID().toString();
} @GetMapping("/token/{userName}")
public String getToken(@PathVariable String userName) { MoUser moUser = new MoUser();
moUser.setUserName(userName);
moUser.setNickName(userName); Map<String, Object> map = new HashMap<>();
map.put(WebConfig.Login_User, moUser); return JwtUtil.getTokenByJson(map,
WebConfig.Token_EncryKey,
WebConfig.Token_SecondTimeOut);
}
}

最终要获通过head传递token值来访问t01接口,得到如下结果:

token在有效时间后访问直接失败,从新获取token并访问t01接口,得到成功的信息:

springboot+jwt做api的token认证的更多相关文章

  1. laravel jwt 做API 退出登录(注销) 该怎么弄? 如何让token失效

    laravel jwt 做API 退出登录(注销) 该怎么弄? 如何让token失效 php框架 laravel 2.1k 次浏览 问题对人有帮助,内容完整,我也想知道答案0问题没有实际价值,缺少关键 ...

  2. tp5使用jwt生成token,做api的用户认证

    首先 composer 安装  firebase/php-jwt github:https://github.com/firebase/php-jwt composer require firebas ...

  3. laravel使用JWT做API认证

    最近项目做API认证,最终技术选型决定使用JWT,项目框架使用的是laravel,laravel使用JWT有比较方便使用的开源包:jwt-auth.php 后端实现JWT认证方法 使用composer ...

  4. Laravel 使用 JWT 做 API 认证之tymon/jwt-auth 1.0.0-beta.1实践 - moell - SegmentFault

    安装 将"tymon/jwt-auth": "1.0.0-beta.1" 添加到 composer.json 中,执行 composer update Prov ...

  5. 【Azure 应用服务】NodeJS Express + MSAL 实现API应用Token认证(AAD OAuth2 idToken)的认证实验 -- passport.authenticate('oauth-bearer', {session: false})

    问题描述 在前两篇博文中,对NodeJS Express应用 使用MSAL + AAD实现用户登录并获取用户信息,获取Authorization信息 ( ID Token, Access Token) ...

  6. Laravel 5 中使用 JWT(Json Web Token) 实现基于API的用户认证

    在JavaScript前端技术大行其道的今天,我们通常只需在后台构建API提供给前端调用,并且后端仅仅设计为给前端移动App调用.用户认证是Web应用的重要组成部分,基于API的用户认证有两个最佳解决 ...

  7. springboot+jwt实现token登陆权限认证

    一 前言 此篇文章的内容也是学习不久,终于到周末有时间码一篇文章分享知识追寻者的粉丝们,学完本篇文章,读者将对token类的登陆认证流程有个全面的了解,可以动态搭建自己的登陆认证过程:对小项目而已是个 ...

  8. JWT(Json web token)认证详解

    JWT(Json web token)认证详解 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该to ...

  9. 程序员过关斩将--更加优雅的Token认证方式JWT

    菜菜,上次你讲的cookie和session认证方式,我这次面试果然遇到了 结果怎么样? 结果面试官问我还有没有更好的方式? 看来你又挂了 别说了,伤心呀.到底还有没有更好的方式呢? 你猜? 基于To ...

随机推荐

  1. 进击Node.js基础(一)

    一.前言 1:Node.js本质上是用chrome浏览器 v8引擎 使用c++编写的JS运行环境 2:相比于JS没有浏览器安全级的限制,额外提供了一些系统级的API:文件读写,进程管理,网络通信等. ...

  2. 系列博文-Three.js入门指南(张雯莉)-照相机

    照相机就是这样一个抽象,它定义了三维空间到二维屏幕的投影方式,用“照相机”这样一个类比,可以使我们直观地理解这一投影方式.而针对投影方式的不同,照相机又分为正交投影照相机与透视投影照相机.我们需要为自 ...

  3. 关于bash

    Linux中有一位名叫"巴士"的tool.他是如何出世的呢?原来,他是一个为GNU计划(GNU计划,又称革奴计划,是由Richard Stallman在1983年9月27日公开发起 ...

  4. Math.pow();Math.sqrt();

    //Math.pow(a,b)功能是a的b次方 (int)Math.sqrt(n):先对n开方,然后转成int类型//例如,(int)Math.sqrt(2)=(int)1.414=1 Math.ab ...

  5. java8中stream的map和flatmap的理解

    转自https://blog.csdn.net/wynjauu/article/details/78741093 假如我们有这样一个需求给定单词列表["Hello","W ...

  6. teeporxy.go

    package,, {         cer, err := tls.LoadX509KeyPair(*tlsCertificate, *tlsPrivateKey)         if err ...

  7. 解锁 vmware esxi 6.7 并安装 mac os 10.13

    1.安装 esxi 6.7 2.下载 unlocker 2.1.1.zip 3.上传 unlocker 2.1.1.zip esxi的磁盘中 4.开启esxi的ssh登录 5.使用 ssh 登录 es ...

  8. NOI前的考试日志

    4.14 网络流专项测试 先看T1,不会,看T2,仙人掌???wtf??弃疗.看T3,貌似最可做了,然后开始刚,刚了30min无果,打了50分暴力,然后接着去看T1,把序列差分了一下,推了会式子,发现 ...

  9. BZOJ_1367_[Baltic2004]sequence_结论题+可并堆

    BZOJ_1367_[Baltic2004]sequence_结论题+可并堆 Description Input Output 一个整数R Sample Input 7 9 4 8 20 14 15 ...

  10. tomcat设置直接通过域名访问项目(不需要接 /项目名)

    本文转自 : https://blog.csdn.net/qq_33647275/article/details/52585489 效果图 打开 tomcat - ->conf- ->se ...