Java实战:实现JWT刷新令牌机制

本文将详细介绍如何在Java应用程序中实现JWT刷新令牌机制。我们将探讨JWT刷新令牌的基本概念,以及如何使用Spring Boot和JWT库来实现认证和授权。此外,我们将通过具体的示例来展示如何在Spring Boot中创建和验证JWT Token,以及如何实现JWT刷新令牌机制。本文适合希望使用JWT刷新令牌机制的Java开发者阅读。

一、引言

在Web应用程序中,安全性是非常重要的一环。JSON Web Token(JWT)是一种轻量级、自包含、基于JSON的认证授权机制,它可以在客户端和服务器之间传递安全信息。JWT通常用于身份验证和授权,但它有一些限制,如Token有效期较短,用户需要频繁重新登录。为了解决这个问题,我们可以实现JWT刷新令牌机制,延长用户的登录状态。

二、JWT刷新令牌的基本概念

1. 什么是JWT刷新令牌?
JWT刷新令牌是一种机制,用于在Token有效期到期之前,为用户生成一个新的Token,从而延长用户的登录状态。刷新令牌通常与访问令牌一起发送给用户,并在Token有效期内使用。
2. JWT刷新令牌的作用

  • 延长用户登录状态:通过为用户生成新的Token,可以避免用户频繁重新登录。
  • 提高系统安全性:刷新令牌可以限制用户在Token有效期内访问系统的能力,降低安全风险。

三、在Spring Boot中实现JWT刷新令牌机制

1. 添加JWT依赖
在项目的pom.xml文件中,添加Spring Boot的JWT依赖:

<dependencies>
    <!-- Spring Boot Web依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring Boot Security依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <!-- JWT依赖 -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
</dependencies>

2. 配置JWT
在Spring Boot中,可以使用JwtConfigurerJwtTokenProvider类来配置JWT。以下是一个简单的JWT配置类示例:

package com.example.demo.config;
import com.example.demo.security.JwtTokenProvider;
import io.jsonwebtoken.security.Keys;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import java.security.Key;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public JwtTokenProvider jwtTokenProvider() {
        return new JwtTokenProvider(key());
    }
    @Bean
    public Key key() {
        return Keys.secretKeyFor(SignatureAlgorithm.HS256);
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/auth/**").permitAll() // 允许所有人访问认证接口
                .anyRequest().authenticated() // 其他请求都需要认证
            .and()
            .apply(jwtTokenFilterConfigurer(jwtTokenProvider()));
    }
}

在上面的代码中,我们创建了一个JWT配置类,它包含了一个JwtTokenProvider Bean,用于生成和验证JWT Token。我们还配置了一个key Bean,用于生成签名。

3. 创建JWT Token过滤器
在Spring Boot中,需要创建一个JWT Token过滤器来验证请求中的Token。以下是一个简单的JWT Token过滤器示例:

package com.example.demo.security;
import com.example.demo.config.JwtConfig;
import com.example.demo.config.JwtTokenProvider;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JwtTokenFilter extends OncePerRequestFilter {
    @Autowired
    private JwtTokenProvider jwtTokenProvider;
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        try {
            String token = jwtTokenProvider.resolveToken(request);
            if (token != null && jwtTokenProvider.validateToken(token)) {
                String username = jwtTokenProvider.getUsernameFromToken(token);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, Collections.emptyList());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (ExpiredJwtException | MalformedJwtException | UnsupportedJwtException | SignatureException e) {
            throw new RuntimeException("Invalid JWT token");
        }
        chain.doFilter(request, response);
    }
}

在上面的代码中,我们创建了一个JwtTokenFilter类,它继承自OncePerRequestFilter并重写了doFilterInternal()方法。这个过滤器会拦截每个请求,并尝试解析和验证请求中的JWT Token。如果Token有效,它会创建一个UsernamePasswordAuthenticationToken对象,并将其设置到安全上下文中。
4. 创建认证接口
在Spring Boot中,创建一个认证接口来处理用户登录请求。以下是一个简单的认证接口示例:

package com.example.demo.controller;
import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AuthController {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtTokenProvider jwtTokenProvider;
    @Autowired
    private UserService userService;
    @PostMapping("/auth/login")
    public ResponseEntity<?> login(@RequestBody User user) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String jwt = jwtTokenProvider.createToken(authentication);
        return ResponseEntity.ok(new JwtAuthenticationResponse(jwt));
    }
}

在上面的代码中,我们创建了一个AuthController类,它包含了一个login方法,用于处理用户登录请求。这个方法会使用AuthenticationManager来验证用户名和密码,如果验证成功,它会创建一个JWT Token并将其返回给客户端。

5. 创建JWT Authentication Response
创建一个简单的响应类,用于返回认证结果和JWT Token。以下是一个简单的响应类示例:

package com.example.demo;
import java.util.Map;
public class JwtAuthenticationResponse {
    private String token;
    private Map<String, Object> additionalInfo;
    public JwtAuthenticationResponse(String token) {
        this.token = token;
    }
    public String getToken() {
        return token;
    }
    public void setToken(String token) {
        this.token = token;
    }
    public Map<String, Object> getAdditionalInfo() {
        return additionalInfo;
    }
    public void setAdditionalInfo(Map<String, Object> additionalInfo) {
        this.additionalInfo = additionalInfo;
    }
}

6. 创建User Service
创建一个用户服务类,用于模拟用户数据的访问。以下是一个简单的用户服务类示例:

package com.example.demo.service;
import com.example.demo.model.User;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserService {
    private static final Map<String, User> users = new HashMap<>();
    static {
        users.put("user", new User("user", "password"));
        users.put("admin", new User("admin", "password"));
    }
    public User findByUsername(String username) {
        return users.get(username);
    }
}

7. 创建User Model
创建一个简单的用户模型类,用于表示用户数据。以下是一个简单的用户模型类示例:

package com.example.demo.model;
public class User {
    private String username;
    private String password;
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

8. 实现JWT刷新令牌机制
为了实现JWT刷新令牌机制,我们需要创建一个刷新令牌的接口,并更新Token的过期时间。以下是一个简单的刷新令牌接口示例:

package com.example.demo.controller;
import com.example.demo.model.JwtAuthenticationResponse;
import com.example.demo.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RefreshTokenController {
    @Autowired
    private AuthService authService;
    @PostMapping("/auth/refresh")
    public ResponseEntity<?> refreshToken(@RequestBody JwtAuthenticationResponse jwtAuthResponse) {
        String token = jwtAuthResponse.getToken();
        String refreshedToken = authService.refreshToken(token);
        JwtAuthenticationResponse response = new JwtAuthenticationResponse(refreshedToken);
        return ResponseEntity.ok(response);
    }
}

AuthService类中,我们需要实现一个refreshToken方法,用于更新Token的过期时间。以下是一个简单的refreshToken方法示例:

package com.example.demo.service;
import com.example.demo.model.JwtAuthenticationResponse;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
public class AuthService {
    private final JwtTokenProvider jwtTokenProvider;
    public AuthService(JwtTokenProvider jwtTokenProvider) {
        this.jwtTokenProvider = jwtTokenProvider;
    }
    public String refreshToken(String token) {
        Claims claims = jwtTokenProvider.getClaimsFromToken(token);
        claims.setExpiration(new Date(System.currentTimeMillis() + jwtTokenProvider.getTokenValidityInMilliseconds()));
        return jwtTokenProvider.createToken(claims);
    }
}

在上面的代码中,我们创建了一个AuthService类,它包含了一个refreshToken方法。这个方法会获取Token中的Claims,并更新其过期时间,然后使用JwtTokenProvider创建一个新的Token。
9. 运行项目
将以上代码添加到我们的Spring Boot项目中,并运行项目。我们可以通过浏览器或Postman等工具访问http://localhost:8080/auth/login,并使用用户名和密码进行登录,观察JWT Token认证授权的效果。同时,我们还可以访问http://localhost:8080/auth/refresh来获取新的Token。

四、总结

本文详细介绍了如何在Java应用程序中实现JWT刷新令牌机制。我们首先了解了JWT刷新令牌的基本概念和作用。然后,我们学习了如何使用Spring Boot和JWT库来实现认证和授权,并通过具体的示例展示了如何在Spring Boot中创建和验证JWT Token,以及如何实现JWT刷新令牌机制。
通过本文,您应该已经掌握了如何实现JWT刷新令牌机制。您学会了如何创建和配置JWT,如何创建JWT Token过滤器,如何创建认证接口,如何实现JWT刷新令牌机制,以及如何使用JWT刷新令牌。希望本文能够帮助您在开发Java应用程序时更加得心应手。如果您有任何疑问或建议,请随时留言交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/408540.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【尚硅谷】MybatisPlus 学习笔记(下)

目录 六、插件 6.1、分页插件 6.1.1、添加配置类 6.1.2、测试 6.2、xml自定义分页 6.2.1、UserMapper中定义接口方法 6.2.2、UserMapper.xml中编写SQL 6.2.3、测试 6.3、乐观锁 6.3.1、场景 6.3.2、乐观锁与悲观锁 6.3.3、模拟修改冲突 数据库中增加商品表 添加数…

LeetCode 第一题: 两数之和

文章目录 第一题: 两数之和题目描述示例 解题思路Go语言实现 - 一遍哈希表法C实现算法分析 排序和双指针法Go语言实现 - 排序和双指针法C算法分析 暴力法Go语言实现 - 暴力法C算法分析 二分搜索法Go语言实现 - 二分搜索法C算法分析 第一题: 两数之和 ‍ 题目描述 给定一个整…

规则持久化(Sentinel)

规则持久化 基于Nacos配置中心实现推送 引入依赖 <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId> </dependency> 流控配置文件 [{"resource":"/order/flow",…

vue+nodejs+uniapp婚纱定制婚庆摄影系统 微信小程序 springboot+python

目前移动互联网大行其道&#xff0c;人人都手中拿着智能机&#xff0c;手机手机&#xff0c;手不离机&#xff0c;如果开发一个用在手机上的程序软件&#xff0c;那是多么的符合潮流&#xff0c;符合管理者和客户的理想。本次就是开发婚庆摄影小程序&#xff0c;有管理员&#…

k8s学习笔记-基础概念

&#xff08;作者&#xff1a;陈玓玏&#xff09; deployment特别的地方在于replica和selector&#xff0c;docker根据镜像起容器&#xff0c;pod控制容器&#xff0c;job、cronjob、deployment控制pod&#xff0c;job做离线任务&#xff0c;pod大多一次性的&#xff0c;cronj…

【蓝桥杯】拓扑排序

一.拓扑排序 1.定义&#xff1a; 设G&#xff08;V&#xff0c;E&#xff09;是一个具有n个顶点的有向图&#xff0c;V中的顶点序列称为一个拓扑序列&#xff0c;当且仅当满足下列条件&#xff1a;若从顶点到有一条路径&#xff0c;则在顶点序列中顶点必在之前。 2.基本思想…

Vue+SpringBoot打造音乐偏好度推荐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.1.1 音乐档案模块2.1.2 我的喜好模块2.1.3 每日推荐模块2.1.4 通知公告模块 2.2 用例图设计2.3 实体类设计2.4 数据库设计 三、系统展示3.1 登录注册3.2 音乐档案模块3.3 音乐每日推荐模块3.4 通知公告模…

【安装】CentOS 7 使用 OUI 图形界面安装 Oracle Database 19.3

需安装使用 X Server 协议的软件&#xff08;如 Xorg&#xff09;和如桌面图形软件&#xff08;Gnome 或 KDE&#xff09;。 使用 root 用户执行&#xff1a; # curl -o oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm https://yum.oracle.com/repo/OracleLinux/OL7/l…

istio系列教程

istio学习记录——安装https://suxueit.com/article_detail/otVbfI0BWZdDRfKqvP3Gistio学习记录——体验bookinfo及可视化观测https://suxueit.com/article_detail/o9VdfI0BWZdDRfKqlv0r istio学习记录——kiali介绍https://suxueit.com/article_detail/pNVbfY0BWZdDRfKqX_0K …

在Node.js中如何实现用户身份验证和授权

当涉及到构建安全的应用程序时&#xff0c;用户身份验证和授权是至关重要的一环。在Node.js中&#xff0c;我们可以利用一些流行的库和技术来实现这些功能&#xff0c;确保我们的应用程序具有所需的安全性。本篇博客将介绍如何在Node.js中实现用户身份验证和授权。 用户身份验…

“激发无限创意:在线图片制作,点亮你的视觉灵感!“

在数字时代&#xff0c;图片已经成为我们表达创意、分享故事和展示个性的重要方式。然而&#xff0c;你是否曾因为缺乏专业的设计技能或繁琐的制作流程而感到困扰&#xff1f;现在&#xff0c;有了在线图片制作平台&#xff0c;释放你的创意灵感变得前所未有的简单和方便&#…

福特锐界2021plus 汽车保养手册

福特锐界2021plus汽车保养手册两页&#xff0c;零部件保养要求&#xff0c;电子版放这里方便查询&#xff1a;

8-pytorch-损失函数与反向传播

b站小土堆pytorch教程学习笔记 根据loss更新模型参数 1.计算实际输出与目标之间的差距 2.为我们更新输出提供一定的依据&#xff08;反向传播&#xff09; 1 MSEloss import torch from torch.nn import L1Loss from torch import nninputstorch.tensor([1,2,3],dtypetorch.fl…

MySQL——基础内容

目录 第01章_数据库概述 关系型数据库(RDBMS)——表、关系模型 非关系型数据库(非RDBMS) 表、记录、字段 表的关联关系 一对一关联 一对多关系 多对多 自我引用 第02章_MySQL环境搭建 登录命令 常用命令 show databases; create database use 数据库名 show tables 第03章…

五种多目标优化算法(MOCS、MOFA、NSWOA、MOAHA、MOPSO)性能对比(提供MATLAB代码)

一、5种多目标优化算法简介 多目标优化算法是用于解决具有多个目标函数的优化问题的一类算法。其求解流程通常包括以下几个步骤&#xff1a; 1. 定义问题&#xff1a;首先需要明确问题的目标函数和约束条件。多目标优化问题通常涉及多个目标函数&#xff0c;这些目标函数可能…

云原生之容器编排实践-kubectl get pod -A没有coredns

背景 前面搭建的3节点 Kubernetes 集群&#xff0c;其实少了一个组件&#xff1a; CoreDNS &#xff0c;这也是我后面拿 ruoyi-cloud 项目练手时&#xff0c;部署了 MySQL 和 Nacos 服务后才意识到的&#xff1a;发现Nacos无法通过服务名连接MySQL&#xff0c;这里 Nacos 选择…

Mac OS 搭建C++开发环境【已解决】

Mac OS 搭建C开发环境 文章目录 Mac OS 搭建C开发环境一、安装命令行工具&#xff1a;二、安装vscode三、安装gcc3.1 安装Homebrew3.2 安装gcc3.3 修改配置 四、更改VSCode默认编译器五、安装gdb六、安装Cmake && git七、编译运行 本地环境&#xff1a; Mac OS Sonoma …

Python中回调函数的理解与应用

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站零基础入门的AI学习网站~。 目录 前言 回调函数的概念 回调函数的基本用法 回调函数的实现方式 1 使用函数 2 使用类方法 3 使用类实…

QWidget: Must construct a QApplication before a QWidget 13:25:48: 程序异常结束。

QWidget: Must construct a QApplication before a QWidget 13:25:48: 程序异常结束。 你的插件是release&#xff0c;而你用了debug模式、