首页 > 其他分享 >JWT在SpringBoot项目中的使用方法与优劣性

JWT在SpringBoot项目中的使用方法与优劣性

时间:2024-11-01 21:18:08浏览次数:6  
标签:String 优劣 JWT springframework private import org SpringBoot

JWT介绍

JWT(JSON Web Token)是一种用于在网络应用环境中安全地传递信息的开放标准(RFC 7519)。它是一种基于 JSON 的令牌格式,广泛用于身份验证和信息交换。

JWT的结构

JWT 通常由三部分组成:头部(Header)、有效载荷(Payload)和签名(Signature)。
这三部分通过 . 字符连接在一起,形成一个字符串header.payload.signature
在这里插入图片描述

Header

通常包含令牌的类型(即 “JWT”)和所使用的签名算法(如 HMAC SHA256 或 RSA)

Payload

包含实际的声明(claims),即要传递的信息。声明可以是预定义的(如 iss、exp 等)或自定义的。
有效载荷部分不加密,因此不应在其中存储敏感信息。

Signature

通过将头部和有效载荷进行编码后,用指定的算法(如 HMAC SHA256)和密钥生成的签名。这个签名用于验证消息的完整性和来源。

JWT的使用

依赖添加

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version> <!-- 检查最新版本 -->
</dependency>

pom.xml文件里添加依赖

创建 JWT 工具类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtUtil {
    private final String SECRET_KEY = "your_secret_key"; // 密钥
    private final long EXPIRATION_TIME = 1000 * 60 * 60; // 设置过期时间

    // 生成 JWT
    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, username);
    }

    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    // 验证 JWT
    public boolean validateToken(String token, String username) {
        final String extractedUsername = extractUsername(token);
        return (extractedUsername.equals(username) && !isTokenExpired(token));
    }

    private String extractUsername(String token) {
        return extractAllClaims(token).getSubject();
    }

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

    private boolean isTokenExpired(String token) {
        return extractAllClaims(token).getExpiration().before(new Date());
    }
}

创建认证控制器

创建一个控制器,用于处理用户登录并返回 JWT

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public String login(@RequestBody AuthRequest authRequest) {
        // 在这里你需要验证用户的用户名和密码
        // 如果验证成功,生成 JWT
        String token = jwtUtil.generateToken(authRequest.getUsername());
        return token;
    }
}

创建请求模型

public class AuthRequest {
    private String username;
    private String password;

    // ... ...
}

配置安全性

与Spring Security整合,每次请求时都验证

import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/api/auth/login").permitAll() // 允许登录请求
            .anyRequest().authenticated(); // 其他请求需要认证

        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

创建 JWT 过滤器

创建一个过滤器,用于在每次请求中解析和验证 JWT

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtRequestFilter extends WebAuthenticationFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserDetailsService userDetailsService;

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

        String username = null;
        String jwt = null;

        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            jwt = authorizationHeader.substring(7);
            username = jwtUtil.extractUsername(jwt);
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);

            if (jwtUtil.validateToken(jwt, userDetails.getUsername())) {
                // 设置用户身份
                // 这里可以设置 Authentication 对象到 SecurityContext
            }
        }
        chain.doFilter(request, response);
    }
}

应用

启动 Spring Boot 应用,使用 Postman 或其他工具发送 POST 请求到 /api/auth/login,并传递用户名和密码,成功后会返回 JWT
在后续的请求中,需要在请求头中添加Authorization 字段

Authorization: Bearer <your_jwt_token>

在这里插入图片描述

JWT的优势

无状态(Stateless)

无状态意味着服务器在处理请求时,不需要存储任何客户端的会话状态。每次请求都是独立的,服务器不会在其内存或数据库中保存关于用户的会话信息。
客户端在后续请求中将 JWT 作为身份凭证发送,服务器只需验证 JWT 的有效性(如签名和过期时间),就可以立即获取用户的身份信息,而无需查询数据库。

减少对数据库的依赖

在传统的会话管理中,服务器通常会在数据库或内存中保存用户的会话信息(如用户ID、权限、登录状态等)。每次请求都需要查找和验证这些信息。这增加了数据库的负担,并可能导致性能瓶颈。
JWT 自包含了所有的用户信息,无需存储在服务器端。令牌中包含的有效载荷可以包括用户的角色、权限等信息,服务器在接收到请求时无需查询数据库来获取用户信息。
由于每个 JWT 令牌都包含所有必要的信息,因此在微服务架构中,服务之间可以相对独立地工作。各个服务可以根据 JWT 中的信息进行身份验证和授权,而不需要访问中央数据库,从而提高了系统的扩展性和响应速度。

JWT的缺点

当登录一个网站时,网站会生成一个JWT给用户,里面包括所有权限信息,之后的每一次通信都会携带此JWT。
那么,如果在此网站,用户点击了退出登录,看似用户下线了,但实际上JWT还未到过期时间,那么此时这个JWT还在有效期内,若JWT被拦截,则会产生安全隐患。
实际上,JWT的缺点不止这些。

大小

我们需要存储一个用户ID 为sienna
如果存储到cookie里面,我们的总大小只有6个字节。
如果我们将 ID 存储在 一个 JWT 里。他的大小就会增加几十倍
这大大增加了宽带负担

令牌撤销

JWT就相当于一个令牌,发出后无法收回,安全性有很大的隐患。
首先,注销并不会使其真的被注销。
其次,信息的更改也不能够及时的同步到令牌上面。

JWT的保密性

JWT的内容不加密,意味着获得针对身份验证凭据的攻击变得容易。

总结

但JWT也是具有很多应用性的,比如单次授权的时候,若考虑长期存储,特别是管理用户会话,JWT会带来很大的安全问题,此时,还是传统的会话机制,比如cookie更加适用。

标签:String,优劣,JWT,springframework,private,import,org,SpringBoot
From: https://blog.csdn.net/weixin_47510148/article/details/143440017

相关文章

  • SpringBoot【实用篇】- 配置高级
    文章目录目标:1.@ConfigurationProperties2.宽松绑定/松散绑定3.常用计量单位绑定4.数据校验目标:@ConfigurationProperties宽松绑定/松散绑定常用计量单位绑定数据校验1.@ConfigurationProperties@ConfigurationProperties在学习yml的时候我们了解到它是可以给......
  • SpringBoot【实用篇】- 热部署
    文章目录目标:1.手动启动热部署2.自动启动热部署4.禁用热部署目标:手动启动热部署自动启动热部署热部署范围配置关闭热部署1.手动启动热部署当我们没有热部署的时候,我们必须在代码修改完后再重启程序,程序才会同步你修改的信息。如果我们想快速查看,那就需要用到......
  • 基于springboot高校社团管理系统设计与实现
    前言系统根据现有的管理模块进行开发和扩展,采用面向对象的开发的思想和结构化的开发方法对高校社团的现状进行系统调查。采用结构化的分析设计,该方法要求结合一定的图表,在模块化的基础上进行系统的开发工作。在设计中采用“自下而上”的思想,在高校社团管理系统实现了学生、......
  • 基于springboot古风生活体验交流网站的设计与实现l
    前言二十一世纪我们的社会进入了信息时代,信息管理系统的建立,大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多,而在线管理系统刚好能满足这些需求,在线管理系统突破了传统管理方式的局限性。于是本文针对这一需求设计并实现了一个基于springboot古风生活体验......
  • 基于java+SpringBoot+Vue的“衣依”服装销售平台设计与实现
    项目运行环境配置:Jdk1.8+Tomcat7.0+Mysql+HBuilderX(Webstorm也行)+Eclispe(IntelliJIDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot+mybatis+Maven+mysql5.7或8.0等等组成,B/S模式+Maven管理等等。环境需要1.运行环境:最好是javajdk1.8,我们在这个......
  • 基于java+SpringBoot+Vue的IT技术交流和分享平台设计与实现
    项目运行环境配置:Jdk1.8+Tomcat7.0+Mysql+HBuilderX(Webstorm也行)+Eclispe(IntelliJIDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot+mybatis+Maven+mysql5.7或8.0等等组成,B/S模式+Maven管理等等。环境需要1.运行环境:最好是javajdk1.8,我们在这个......
  • 基于SpringBoot的考试安排管理系统的设计和实现(源码+LW+调试文档)
     目录:完整视频演示:系统架构:程序运行截图:核心代码参考:   数据库sql:项目技术介绍:java介绍:Mysql数据库介绍:为什么选择我:获取源码:......
  • 基于SpringBoot的高考择校推荐系统的设计和实现(源码+LW+调试文档)
     目录:完整视频演示:系统架构:程序运行截图:核心代码参考:   数据库sql:项目技术介绍:java介绍:Mysql数据库介绍:为什么选择我:获取源码:......
  • 基于springboot的Java学习论坛平台
    基于springboot的Java学习论坛平台摘要在Internet高速发展的今天,我们生活的各个领域都涉及到计算机的应用,其中包括学习平台的网络应用,在外国学习平台已经是很普遍的方式,不过国内的管理平台可能还处于起步阶段。学习平台具有学习信息管理功能的选择。学习平台采用java技术......
  • 【SpringSecurity-2】Springboot + SpringSecurity + Oauth2授权码模式
    目录1、项目验证(1)获取授权码(2)获取access_token2、添加资源服务器(1)创建项目(2)添加依赖(3)创建启动类(4)配置资源服务器(5)创建Rest接口(6)添加application.yml3、获取token,访问资源服务器(1)授权服务器的修改(2)资源服务器token校验方式本篇接上篇内容,拿到授权码后,客户端往......