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日

相关文章

  • Sprint Boot @RestController使用方法详解

    @RestController是Spring Boot中的一个注解,它用于标记一个类,表示该类是一个RESTful风格的控制器。在使用Spring Boot开发Web应用程序时,@RestController是非常重要的。本文将详细介绍@RestController的作用和使用方法,并提供两个示例说明。 @RestController的作用 @RestCon…

    Java 2023年5月5日
    00
  • 基于hibernate实现的分页技术实例分析

    下面我来详细讲解“基于hibernate实现的分页技术实例分析”的完整攻略。 什么是Hibernate分页技术? Hibernate分页实际上就是在一个查询语句中指定起始位置和查询数量,获取查询结果的过程。在大多数情况下,我们不可能将整张数据表中的所有数据都查询出来,这样不仅浪费时间和空间,而且会影响系统响应速度。所以,分页查询就成了一个很常见的需求。 如何…

    Java 2023年5月20日
    00
  • Java 中Map 的用法详解

    Java 中 Map 的用法详解 简介 Map 是 Java 中常见的一种数据结构,它存储了一组键值对,其中每个键都唯一对应一个值,而多个键可以对应同一个值。在 Map 中,通过键快速定位对应的值,相对于遍历数组或者列表来说,速度更快。在 Java 中,Map 接口有多个实现类,其中常用的有 HashMap 和 TreeMap。 常用方法介绍 1. put …

    Java 2023年5月26日
    00
  • Java 中EasyExcel的使用方式

    Java 中EasyExcel的使用方式 什么是EasyExcel EasyExcel 是阿里巴巴开源的一个 Java 操作 Excel 的简单工具,具有自动识别 Excel 文件的类型(2003/2007/2010等)及生成 Excel 文件,读取数据和流式写入数据的功能。为我们处理 Excel 带来了很大的便利性。 EasyExcel 的使用方式 1. …

    Java 2023年5月19日
    00
  • SpringBoot+Spring Data JPA整合H2数据库的示例代码

    下面我将为您提供“SpringBoot+Spring Data JPA整合H2数据库的示例代码”的详细攻略: 确保本地已经安装好JDK和Maven 创建一个SpringBoot项目,使用Maven构建,在pom.xml中引入以下相关依赖: <dependency> <groupId>org.springframework.boot&l…

    Java 2023年5月20日
    00
  • Java实现文件读取和写入过程解析

    Java实现文件读取和写入过程解析 在Java中,读取和写入文件是非常常见的操作,本文将详细介绍Java实现文件读取和写入的过程,并提供两个示例进行演示。 文件读取 文件读取可以使用Java标准库中提供的java.io包中的FileReader和BufferedReader类实现。 FileReader类用于读取字符文件,BufferedReader类可以优…

    Java 2023年5月20日
    00
  • Java实现雪花算法(snowflake)

    Java实现雪花算法(snowflake) 雪花算法是一种可以生成全局唯一ID的算法,它可以用于分布式系统中的ID生成。下面是Java实现雪花算法(snowflake)的完整攻略,包含过程中至少两条示例说明。 算法思路 雪花算法可以生成64位的唯一ID,其生成规则如下: 1位标识符:符号位,在雪花算法中始终为0,表示正数。 41位时间戳:记录生成ID的时间,…

    Java 2023年5月18日
    00
  • JAVA JNI函数的注册过程详细介绍

    JNI(Java Native Interface)是Java向底层语言(如C、C++)展示其本地方法(Native Method)能力的桥梁,因此在使用JNI时需要将Java方法与本地C/C++函数进行关联,这便是JNI函数的注册过程。 JNI函数的注册流程如下: 1.在C/C++文件中,定义实现Java方法的本地函数。 2.使用javah命令生成与本地函…

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