本篇和大家分享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. ubuntu旧版本源失效的处理方法

    (1)先备份 cp /etc/apt/sources.list /etc/apt/sources.list_backup (2)更换源 在ubuntu的网站中,提供了一个源供那些不再提供支持的版本使用 ...

  2. 在线OJ使用总结(acm)

    赛码网OJ规则 用readLine()代替read_line() 用readLine()代替read_line() 用readLine()代替read_line() 用readLine()代替read ...

  3. 跟我学ASP.NET MVC之一:开篇有益

    摘要: ASP.NET MVC是微软的Web开发框架,结合了模型-视图-控制器(MVC)架构的有效性和整洁性,敏捷开发最前沿的思想和技术,以及现存的ASP.NET平台最好的部分.它是传统ASP.NET ...

  4. 接口测试返回的json文件中字符串是乱序

    问题描述 接口测试中post方式匹配返回信息时显示不匹配, 但是statuscode明明是200, 而且用postman /restclient等工具测出来也是没问题的. 根本原因 封装了这么个方法来 ...

  5. 借助HTML中的特殊符号在markdown中打印出来

    转自:https://blog.csdn.net/html5_/article/details/21639475 HTML中的特殊符号 原创 2014年03月20日 18:35:23 标签: HTML ...

  6. TestNG教程网站

    比较简明的一些TestNG教程网站 : https://www.jianshu.com/p/74816a200221 http://www.yiibai.com/testng/parameterize ...

  7. BZOJ_4518_[Sdoi2016]征途_斜率优化

    BZOJ_4518_[Sdoi2016]征途_斜率优化 Description Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到 ...

  8. BZOJ_1800_[Ahoi2009]fly 飞行棋_乱搞

    BZOJ_1800_[Ahoi2009]fly 飞行棋_乱搞 Description 给出圆周上的若干个点,已知点与点之间的弧长,其值均为正整数,并依圆周顺序排列. 请找出这些点中有没有可以围成矩形的 ...

  9. tomcat部署服务乱码问题

    first:win+R -->输入regedit 打开注册列表HKEY_CURRENT_USER-->Console-->Tomcat-->CodePage修改成十进制6500 ...

  10. 从壹开始前后端分离【 .NETCore2.1 +Vue 2 +AOP+DI】框架之一 || 前言

    缘起 作为一个.Net攻城狮已经4年有余了,一直不温不火,正好近来项目不是很忙,闲得无聊,搞一搞新技术,一方面是打发无聊的时间,一方面也是督促自己该学习辣!身边的大神都转行的转行,加薪的加薪,本人比较 ...