SpringSecurity Jwt Token 自动刷新的实现

下面是SpringSecurity Jwt Token 自动刷新的实现的完整攻略。

1. 什么是Jwt Token?

Jwt Token(也称为 Json Web Token)是一种基于 JSON 格式的身份验证标准。通常用于 RESTful API,作为一种简单、轻量级的身份验证机制,用于跨域身份验证,以及在分布式系统中传递身份信息。它包含了三部分: Header、Payload 和 Signature。其中,Header 和 Payload 部分都是 Base64Url 编码的 JSON 字符串,Signature 是将 Header、Payload 和一个加密密钥进行签名得到的字符串。

2. Jwt Token 有哪些优势?

  • 跨域身份验证:因为 Jwt Token 包含了身份验证信息,可以轻松在不同的域之间传递身份验证信息。

  • 无状态:因为 Jwt Token 包含了所有必要的信息,可以不需要在服务器端保存任何信息,从而使服务器更加容易扩展。

  • 自包含:Jwt Token 包含了所有必要的信息,因此客户端可以验证 Jwt Token 的有效性,而无需向服务器发出任何请求。

3. SpringSecurity Jwt Token 自动刷新的实现

3.1 环境准备

首先,需要在项目中添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

同时,在 Spring Security 的配置类中,需要添加如下配置:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable().authorizeRequests().antMatchers("/authenticate").permitAll()
            .anyRequest().authenticated().and().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

其中,jwtRequestFilter 是我们自己实现的 Jwt Token 过滤器,用于验证 Jwt Token。

3.2 实现 Jwt Token 过滤器

为了实现 Jwt Token 过滤器,我们需要实现 OncePerRequestFilter 接口,并 Override doFilterInternal 方法。在该方法中,我们解析 Jwt Token,并验证其有效性。

以下是示例代码:

@Component
public class JwtRequestFilter extends OncePerRequestFilter {
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        final String requestTokenHeader = request.getHeader("Authorization");

        String username = null;
        String jwtToken = null;

        // JWT Token is in the form "Bearer token". Remove Bearer word and get
        // only the Token
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = jwtTokenUtil.getUsernameFromToken(jwtToken);
            } catch (IllegalArgumentException e) {
                logger.warn("Unable to get JWT Token");
            } catch (ExpiredJwtException e) {
                logger.warn("JWT Token has expired");
            }
        } else {
            logger.warn("JWT Token does not begin with Bearer String");
        }

        // Once we get the token validate it.
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

            // if token is valid configure Spring Security to manually set
            // authentication
            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
}

3.3 实现 Jwt Token 的自动刷新

为了实现 Jwt Token 的自动刷新,我们需要在 Jwt Token 过滤器中对过期的 Jwt Token 进行处理。具体而言,我们可以在每次验证 Jwt Token 的时候,检查 Jwt Token 是否快要过期,如果快要过期,就重新生成一个 Jwt Token,并将它添加到响应的头信息中。客户端收到这个响应之后,就会使用新的 Jwt Token 代替旧的 Jwt Token,从而实现自动刷新。

以下是示例代码:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    final String requestTokenHeader = request.getHeader("Authorization");

    String username = null;
    String jwtToken = null;

    // JWT Token is in the form "Bearer token". Remove Bearer word and get
    // only the Token
    if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
        jwtToken = requestTokenHeader.substring(7);
        try {
            username = jwtTokenUtil.getUsernameFromToken(jwtToken);
        } catch (IllegalArgumentException e) {
            logger.error("Unable to get JWT Token");
        } catch (ExpiredJwtException e) {
            logger.warn("JWT Token has expired");
        }
    } else {
        logger.warn("JWT Token does not begin with Bearer String");
    }

    // Once we get the token validate it.
    if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
        UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

        // if token is valid configure Spring Security to manually set
        // authentication
        if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities());
            usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

            // 如果发现 Jwt Token 即将过期
            if(jwtTokenUtil.isTokenAboutToExpire(jwtToken)) {
                // 重新生成一个 Jwt Token
                String refreshedToken = jwtTokenUtil.refreshToken(jwtToken);

                // 设置响应的头信息
                response.setHeader("Authorization", "Bearer " + refreshedToken);
            }
        }
    }
    chain.doFilter(request, response);
}

4. 总结

通过实现 Jwt Token 的自动刷新,我们可以保持用户的登录状态,同时避免 Jwt Token 过期而导致的用户需再次登录的情况。如有需要,我们可以自己实现一个简单的 Jwt Token 工具类。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringSecurity Jwt Token 自动刷新的实现 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • java 易懂易用的MD5加密(可直接运行)(2)

    下面是完整的攻略: Java易懂易用的MD5加密(可直接运行)(2) 背景信息 本篇攻略是 “Java易懂易用的MD5加密(可直接运行)(1)” 的续篇,如需了解更多背景信息请先查阅前篇攻略。 攻略步骤 1. 导入依赖包 首先,我们需要先导入依赖包。在本篇攻略中,我们使用的是commons-codec依赖包,该包中包含了Java中常用的摘要算法、编码器和哈希…

    Java 2023年6月15日
    00
  • Java中难理解的四个概念

    下面是讲解Java中难理解的四个概念的攻略。 1. 非静态内部类和静态内部类 对于Java中的内部类,可以分为两种类型:非静态内部类和静态内部类。 非静态内部类的创建需要依赖于外部类的实例,而静态内部类则不需要。简单来说,非静态内部类可以访问外部类的非静态成员和方法,而且可以直接访问外部类的实例变量。静态内部类则不能直接访问外部类的实例变量和非静态成员,但可…

    Java 2023年5月26日
    00
  • java生成jar包的方法

    生成 Java 的 JAR 包一般有两种方法,下面我会为你详细讲解。 方法一:通过命令行生成 JAR 包 首先,我们需要将我们的 Java 代码编译成字节码文件,使用下列代码将 “Example.java” 编译为 “Example.class”: javac Example.java 接下来,我们需要创建一个 MANIFEST.MF 文件。在此文件中需要包…

    Java 2023年5月19日
    00
  • 监控微信小程序中的慢HTTP请求过程详解

    下面我来详细讲解“监控微信小程序中的慢HTTP请求过程详解”的完整攻略。 相关概念 在开始讲解之前,先介绍一些相关的概念: HTTP请求时间 表示从发出HTTP请求到收到响应所经过的时间。 DNS解析时间 表示从发出HTTP请求到获得目标服务器的IP地址所需的时间。 TCP连接时间 表示从发出HTTP请求到与目标服务器建立TCP连接所需的时间。 SSL/TL…

    Java 2023年5月23日
    00
  • java调用shell命令并获取执行结果的示例

    下面是详细讲解“java调用shell命令并获取执行结果的示例”的完整攻略。 1. Java如何调用Shell命令 在Java中执行Shell命令,可以使用Runtime或ProcessBuilder类。 1.1 使用Runtime类调用Shell命令 String command = "ls -l"; Runtime runtime =…

    Java 2023年5月26日
    00
  • 分布式医疗挂号系统SpringCache与Redis为数据字典添加缓存

    接下来我将为您详细讲解“分布式医疗挂号系统SpringCache与Redis为数据字典添加缓存”的完整攻略。 简介 分布式医疗挂号系统是一种可以为病人提供在线挂号、医生排队、诊断和用药等创新医疗系统。在此系统中,我们照常将业务逻辑和数据库中已缓存的数据保留存储,以便我们能够快速存取数据并提高网站的访问速度。这就需要我们利用缓存技术为数据字典添加缓存。这里将演…

    Java 2023年5月19日
    00
  • SpringBoot2零基础到精通之数据与页面响应

    SpringBoot2 零基础到精通之数据与页面响应 SpringBoot是一款快速开发框架,它的特点在于能够自动配置和约定大于配置。通过本文,你将学会: 在SpringBoot项目中,利用控制器将数据响应到页面上; 配置模板引擎,在页面上渲染动态数据; 将数据响应成Json,供前端异步获取。 1. 添加依赖 在你的SpringBoot项目的pom.xml文…

    Java 2023年5月19日
    00
  • fastjson序列化时间自定义格式示例详解

    FastJson序列化时间自定义格式示例详解 在使用FastJson进行序列化时,我们有时需要对日期类型进行格式化,以满足项目需求,本文将详细讲解FastJson序列化时间的自定义格式方法。 一、使用JsonField注解自定义时间格式 FastJson提供了@JSONField注解,通过该注解可以对Java对象进行序列化并指定时间格式。 import co…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部