SpringBoot集成JWT实现权限认证
上一篇文章《一分钟带你了解jwt认证!》介绍了jwt的组成和认证原理,本文将介绍下springboot整合jwt实现认证的过程,带你更深入的了解下jwt。
一、jwt认证流程
认证流程如下:
- 用户使用账号和密码发出post请求;
- 服务器使用私钥创建一个jwt;
- 服务器返回这个jwt给浏览器;
- 浏览器将该jwt串在请求头中像服务器发送请求;
- 服务器验证该jwt;
- 返回响应的资源给浏览器。
二、springboot整合jwt
新建一个spring boot项目spring-boot-jwt,按照下面步骤操作。
1.pom.xml引入jar包
<!-- 引入jwt--> <dependency> <groupid>com.auth0</groupid> <artifactid>java-jwt</artifactid> <version>3.8.2</version> </dependency>
2.新建jwt工具类
jwt工具类进行token的生成和认证,工具类代码如下:
/** * @description: jwt工具类,生成jwt和认证 * @author: java碎碎念 */ public class jwtutil { private static final logger logger = loggerfactory.getlogger(jwtutil.class); /** * 密钥 */ private static final string secret = "my_secret"; /** * 过期时间 **/ private static final long expiration = 1800l;//单位为秒 /** * 生成用户token,设置token超时时间 */ public static string createtoken(user user) { //过期时间 date expiredate = new date(system.currenttimemillis() + expiration * 1000); map<string, object> map = new hashmap<>(); map.put("alg", "hs256"); map.put("typ", "jwt"); string token = jwt.create() .withheader(map)// 添加头部 //可以将基本信息放到claims中 .withclaim("id", user.getid())//userid .withclaim("username", user.getusername())//username .withclaim("name", user.getname())//name .withexpiresat(expiredate) //超时设置,设置过期的日期 .withissuedat(new date()) //签发时间 .sign(algorithm.hmac256(secret)); //secret加密 return token; } /** * 校验token并解析token */ public static map<string, claim> verifytoken(string token) { decodedjwt jwt = null; try { jwtverifier verifier = jwt.require(algorithm.hmac256(secret)).build(); jwt = verifier.verify(token); } catch (exception e) { logger.error(e.getmessage()); logger.error("token解码异常"); //解码异常则抛出异常 return null; } return jwt.getclaims(); } }
3.添加jwt过滤器
jwt过滤器中进行token的校验和判断,,token不合法直接返回,合法则解密数据并把数据放到request*后续使用。
为了使过滤器生效,需要在启动类添加注解@servletcomponentscan(basepackages = "com.example.springbootjwt.filter")。
jwt过滤器代码如下:
/** * jwt过滤器,拦截 /secure的请求 */ @slf4j @webfilter(filtername = "jwtfilter", urlpatterns = "/secure/*") public class jwtfilter implements filter { @override public void init(filterconfig filterconfig) throws servletexception { } @override public void dofilter(servletrequest req, servletresponse res, filterchain chain) throws ioexception, servletexception { final httpservletrequest request = (httpservletrequest) req; final httpservletresponse response = (httpservletresponse) res; response.setcharacterencoding("utf-8"); //获取 header里的token final string token = request.getheader("authorization"); if ("options".equals(request.getmethod())) { response.setstatus(httpservletresponse.sc_ok); chain.dofilter(request, response); } // except options, other request should be checked by jwt else { if (token == null) { response.getwriter().write("没有token!"); return; } map<string, claim> userdata = jwtutil.verifytoken(token); if (userdata == null) { response.getwriter().write("token不合法!"); return; } integer id = userdata.get("id").asint(); string name = userdata.get("name").asstring(); string username = userdata.get("username").asstring(); //拦截器 拿到用户信息,放到request中 request.setattribute("id", id); request.setattribute("name", name); request.setattribute("username", username); chain.dofilter(req, res); } } @override public void destroy() { } }
4.添加登录controller
登录controller进行登录操作,登录成功后生产token并返回。
登录controller代码如下:
/** * 登录controller */ @slf4j @restcontroller public class logincontroller { static map<integer, user> usermap = new hashmap<>(); static { //模拟数据库 user user1 = new user(1, "zhangsan", "张三", "123456"); usermap.put(1, user1); user user2 = new user(2, "lisi", "李四", "123123"); usermap.put(2, user2); } /** * 模拟用户 登录 */ @requestmapping("/login") public string login(user user) { for (user dbuser : usermap.values()) { if (dbuser.getusername().equals(user.getusername()) && dbuser.getpassword().equals(user.getpassword())) { log.info("登录成功!生成token!"); string token = jwtutil.createtoken(dbuser); return token; } } return ""; } }
5.添加securecontroller
securecontroller中的请求会被jwt过滤器拦截,合法后才能访问。
securecontroller代码如下:
/** * 需要登录后才能访问 */ @slf4j @restcontroller public class securecontroller { /** * 查询 用户信息,登录后才能访问 */ @requestmapping("/secure/getuserinfo") public string login(httpservletrequest request) { integer id = (integer) request.getattribute("id"); string name = request.getattribute("name").tostring(); string username = request.getattribute("username").tostring(); return "当前用户信息id=" + id + ",name=" + name + ",username=" + username; } }
三、测试
测试分两步,首先访问登录接口,登录成功后获取token,然后拿着token在访问查询用户信息接口。
1.访问登录接口
打开postman,访问http://localhost:8080/login?username=zhangsan&password=123456,登录成功后接口返回token,请求成功截图如下:
2.访问用户信息接口
打开postman,访问http://localhost:8080/secure/getuserinfo,header里需要携带token,请求成功截图如下:
到此springboot整合jwt的功能已经全部实现,有问题欢迎留言沟通哦!
完整源码地址: https://github.com/suisui2019/springboot-study
推荐阅读
-
Django集成OpenLDAP认证的实现
-
SpringBoot+JWT实现登录权限控制(代码)
-
Django+JWT实现Token认证的实现方法
-
SpringBoot2.0 整合 Shiro 框架,实现用户权限管理
-
SpringBoot2.0 整合 SpringSecurity 框架,实现用户权限安全管理
-
django认证系统实现自定义权限管理的方法
-
Springboot shiro认证授权实现原理及实例
-
SpringBoot使用AOP+注解实现简单的权限验证的方法
-
详解Spring Boot实战之Filter实现使用JWT进行接口认证
-
Vue+Jwt+SpringBoot+Ldap完成登录认证的示例代码