欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot集成JWT实现权限认证

程序员文章站 2022-06-07 12:18:47
上一篇文章 "《一分钟带你了解JWT认证!》" 介绍了JWT的组成和认证原理,本文将介绍下SpringBoot整合JWT实现认证的过程,带你更深入的了解下JWT。 [TOC] 一、JWT认证流程 认证流程如下: 1. 用户使用账号和密码发出post请求; 2. 服务器使用私钥创建一个jwt; 3. ......

上一篇文章《一分钟带你了解jwt认证!》介绍了jwt的组成和认证原理,本文将介绍下springboot整合jwt实现认证的过程,带你更深入的了解下jwt。

一、jwt认证流程

SpringBoot集成JWT实现权限认证

认证流程如下:

  1. 用户使用账号和密码发出post请求;
  2. 服务器使用私钥创建一个jwt;
  3. 服务器返回这个jwt给浏览器;
  4. 浏览器将该jwt串在请求头中像服务器发送请求;
  5. 服务器验证该jwt;
  6. 返回响应的资源给浏览器。

二、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,请求成功截图如下:

SpringBoot集成JWT实现权限认证

2.访问用户信息接口

打开postman,访问http://localhost:8080/secure/getuserinfo,header里需要携带token,请求成功截图如下:

SpringBoot集成JWT实现权限认证

到此springboot整合jwt的功能已经全部实现,有问题欢迎留言沟通哦!

完整源码地址: https://github.com/suisui2019/springboot-study