百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

若依开发框架解析笔记(7)-jwt的应用

ccwgpt 2024-09-13 16:02 52 浏览 0 评论

这篇讲一下若依框架认证所用的jwt技术。若依前后端分离的框架,不同于以前的单体的web应用的架构,可以把session存储在服务器的内存中,浏览器访问的时候通过cookie携带相关的认证信息,服务器可以去通过cookie里面的值去判断该请求是否已经经过认证。这个 session技术也有一定的弊端,就是session被存储在了服务器内容中,对于内存有较大的压力,并且后台有多个server的情况下,还需要负载均衡有会话保持的功能。

对于session的存储,也有把 session存储在redis中,这样虽然解决了对于服务器内存的压力,和服务器无状态的情况,但是这样使得系统对于redis的依赖也加重了。

由于现在采用了前后端分离的技术,后台服务器不会直接与客户端接触,后台服务器只是会与前端服务器进行交互,一般性的会话保持肯定是不可行的,后端的服务器对于前端发过来的请求肯定是没有保持状态一说了,所以有了不同于session的认证技术了。

若依框架使用了jwt(Json Web Token)技术,来进行登录和鉴权。主要的流程有这么几步:

登录成功之后,服务器端验证通过返回jwt的字符串给客户端
客户端再发起请求之后,会在请求头里面带上jwt的内容
服务器验证jwt中的内容

这个与session的区别在于服务器端不会存储生成的token,服务器负责生成和解析。

我们可以通过浏览器的开发者模式观察一下,登录之后的返回内容:

返回的那个token就是后续用于鉴权使用的。可以看到jwt的格式是一个字符串,用"."分隔成3部分。

若依框架用了jjwt这个库来实现了token的生成和解析。

       <!-- Token生成与解析-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>

首先关注一下工程中配置文件的部分,首先定义了在http请求头中的标识,令牌的密钥,和有效时长。

# token配置
token:
    # 令牌自定义标识
    header: Authorization
    # 令牌密钥
    secret: abcdefghijklmnopqrstuvwxyz
    # 令牌有效期(默认30分钟)
    expireTime: 30

下一步,我们准备分析一下框架里面的源码,主要的关注的功能是两个,一个是生成token,另外一个则是解析。TokenService.java这个类是主要的要关注的。首先是从配置文件中读取token相关的配置。

 // 令牌自定义标识
    @Value("${token.header}")
    private String header;

    // 令牌秘钥
    @Value("${token.secret}")
    private String secret;

    // 令牌有效期(默认30分钟)
    @Value("${token.expireTime}")
    private int expireTime;

createToken这个方法是核心的一个方法,用于生成token,这里很多都是调用了现有的一些工具,我们主要关注一下实现的流程。首先产生一个随机id,然后再进行一些登录信息的设置,然后再更新token,最后调用jwt 的工具生成token,签名算法是 HS512

    /**
     * 创建令牌
     *
     * @param loginUser 用户信息
     * @return 令牌
     */
    public String createToken(LoginUser loginUser)
    {
        String token = IdUtils.fastUUID();
        loginUser.setToken(token);
        setUserAgent(loginUser);
        refreshToken(loginUser);

        Map<String, Object> claims = new HashMap<>();
        claims.put(Constants.LOGIN_USER_KEY, token);
        return createToken(claims);
    }
private String createToken(Map<String, Object> claims)
    {
        String token = Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, secret).compact();
        return token;
    }

再看一下验证token的源码。会先获取当前的系统时间,,相差不足20分钟,自动刷新缓存,通过刷新缓存的方法,会把内容刷入redis中。

    public void verifyToken(LoginUser loginUser)
    {
        long expireTime = loginUser.getExpireTime();
        long currentTime = System.currentTimeMillis();
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
        {
            refreshToken(loginUser);
        }
    }

下一部分是验证token:

验证token是结合了SpringSecurity,使用了JwtAuthenticationTokenFilter这个过滤器来进行解析。

第一步是获取请求里面的token,从里面获取对应的用户和权限信息。

    public LoginUser getLoginUser(HttpServletRequest request)
    {
        // 获取请求携带的令牌
        String token = getToken(request);
        if (StringUtils.isNotEmpty(token))
        {
            try
            {
                Claims claims = parseToken(token);
                // 解析对应的权限以及用户信息
                String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
                String userKey = getTokenKey(uuid);
                LoginUser user = redisCache.getCacheObject(userKey);
                return user;
            }
            catch (Exception e)
            {
            }
        }
        return null;
    }

里面的一步是获取请求头里面的token

    private String getToken(HttpServletRequest request)
    {
        String token = request.getHeader(header);
        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
        {
            token = token.replace(Constants.TOKEN_PREFIX, "");
        }
        return token;
    }

获取到token 之后就是解析,这里也是调用现有的库。

    private Claims parseToken(String token)
    {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

解析完之后,后面就是验证token,有效的话就会刷新时效,如果是无效的话,会在过滤器中抛出异常。

再用户退出之后,若依框架对于token的处理是对token进行删除,相关的代码在LogoutSuccessHandlerImpl.java中。

@Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException
    {
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(loginUser))
        {
            String userName = loginUser.getUsername();
            // 删除用户缓存记录
            tokenService.delLoginUser(loginUser.getToken());
            // 记录用户退出日志
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
        }
        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.SUCCESS, "退出成功")));
    }

总结一下,这里使用了jwt作为认证的框架,jwt是否比传统的session-cookie一定适合web应用还是存在疑问的,本篇文章仅仅研究很分析了一下这个框架使用jwt的基本流程。

相关推荐

腾讯开源框架TarsCpp-rpc设计分析-server(二)

2Tars协议2.1是什么借用官方说法:TARS编码协议是一种数据编解码规则,它将整形、枚举值、字符串、序列、字典、自定义结构体等数据类型按照一定的规则编码到二进制数据流中。对端接收到二进制数据流...

微服务调用为什么用RPC框架,http不更简单吗?

简单点,HTTP是协议,RPC是概念!实现RPC可以基于HTTP协议(Feign),TCP协议(Netty),RMI协议(Soap),WebService(XML—RPC)框架。传输过程中,也因为序列...

go-zero:开箱即用的微服务框架(gin框架微服务)

go-zero是一个集成了各种工程实践的Web和rpc框架,它的弹性设计保障了大并发服务端的稳定性,并且已经经过了充分的实战检验。go-zero在设计时遵循了“工具大于约定和文档”的理...

SOFARPC :高性能、高扩展性、生产级的 Java RPC 框架

#暑期创作大赛#SOFARPC是一个高性能、高扩展性、生产级的JavaRPC框架。在蚂蚁金服,SOFARPC已经使用了十多年,已经发展了五代。SOFARPC致力于简化应用程序之间的RPC...

自研分布式高性能RPC框架及服务注册中心ApiRegistry实践笔记

痛点1.bsf底层依赖springcloud,影响bsf更新springboot新版本和整体最新技术版本升级。2.eureka已经闭源,且框架设计较重,同时引入eureka会自行引入较多sprin...

Rust语言从入门到精通系列 - Tonic RPC框架入门实战

Rust语言是一种系统级语言,被誉为“没有丧失性能的安全语言”。Rust语言的优势在于其内存安全机制,在编译时就能保证程序的内存安全。Tonic模块是Rust语言的一个RPC(RemoteProce...

腾讯开源框架TarsCpp-rpc设计分析-client(一)

前言Tars是腾讯开源的微服务平台,包含了一个高性能的rpc框架和服务治理平台,TarsCpp是其C++版本。对于以C++为主要开发语言,同时还想深入了解rpc和微服务框架具体实现的同学来说,Tars...

设计了一款TPS百万级别的分布式、高性能、可扩展的RPC框架

为啥要开发RPC框架事情是这样的,在开发这个RPC框架之前,我花费了不少时间算是对Dubbo框架彻底研究透彻了。冰河在撸透了Dubbo2.x和Dubbo3.x的源码之后,本来想给大家写一个Dubbo源...

rpc框架使用教程,超级稳定好用,大厂都在使用

rpc是什么远程调用协议如何使用导入依赖<dependency><groupId>org.apache.dubbo</groupId><art...

Layui 框架实战:动态加载 Select 与二级联动全解析

在现代Web开发中,下拉选择框(Select)是用户输入数据时不可或缺的组件。很多时候,我们需要的选项并非静态写死在HTML中,而是需要根据业务逻辑从后端动态获取。更有甚者,我们可能需要实现“...

15个能为你节省数百小时的前端设计神器,从UI库到文档生成

无论你是刚开始开发之旅的新手,还是疲于应付生产期限的资深程序员,有一个真理始终不变:正确的工具能彻底改变你的工作流程。多年来,我测试了数百个开发工具——有些实用,大多数平庸。但有一批免费网站经受住了时...

Layui与WinForm通用权限管理系统全解析

嘿,小伙伴们,今天咱们来聊聊Layui和WinForm这两个框架在通用权限管理系统中的应用。别担心,我会尽量用简单易懂的语言来讲解,保证让大家都能跟上节奏!首先说说Layui。Layui是一个前端UI...

纯Python构建精美UI!MonsterUI让前端开发效率飙升

“无需CSS知识,告别类名记忆,11行代码实现专业级卡片组件”在传统Web开发中,构建美观界面需要同时掌握HTML、CSS、JavaScript三剑客,开发者不得不在多种语言间频繁切换。即使使用Boo...

WebTUI:将终端用户界面(TUI)之美带到浏览器的CSS库

在当今Web技术飞速发展的时代,界面设计愈发复杂多样。然而,随着现代化工具的广泛使用,一些开发者开始回归极简风格,追求一种简洁而富有韵味的设计。WebTUI正是这样一款CSS库,它将经典的终...

人教版二年级下册生字描红汇总(拼音+笔顺+描红),可打印!

可定制内容,评论区留言。本次整理的为人教版二年级下册所有生字,共计300个;写字是小学阶段一项重要的基本功训练,把汉字写得正确、工整、美观,可以提高运用汉字这一交际工具的准确性和效率。对小学生进行写字...

取消回复欢迎 发表评论: