Java中JWT(JSON Web Token)的运用具体案例
前言
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用环境间以紧凑的方式安全地传递信息。JWT可以被用作身份验证和信息交换的手段,特别适合用于前后端分离的应用程序。
1. JWT的结构
JWT由三部分组成:
Header(头部): 通常包含令牌的类型(JWT)和所使用的签名算法(如HMAC SHA256或RSA)。
Payload(负载): 包含声明(claims),即要传递的数据。其中可以包含注册声明(如 iss、exp、sub 等)和自定义声明。
Signature(签名): 用于验证消息的完整性和发送者的身份。通过将编码后的header和payload与一个密钥结合,利用指定的算法生成。
JWT的格式如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
2. JWT的优点
- 无状态: 不需要在服务器存储会话信息,减轻了服务器的负担。
- 跨域: 可以在不同的域之间进行身份验证。
- 自包含: 含有用户身份信息,避免频繁查询数据库。
3. JWT的流转过程
- 用户通过登录接口发送用户名和密码。
- 服务器验证用户信息,如果成功,则生成JWT并返回给用户。
- 用户在后续请求中带上JWT,通常放在HTTP请求的Authorization头中。
- 服务器解析JWT,验证其有效性,允许或拒绝请求。
4.具体案例
好的,让我们更详细地探讨如何在Java Spring Boot应用程序中实现JWT身份验证,包括每一步的代码和说明。
一、项目结构
Spring Boot项目结构如下:
src ├── main │ ├── java │ │ └── com │ │ └── example │ │ └── jwt │ │ ├── JwtApplication.java │ │ ├── config │ │ │ └── SecurityConfig.java │ │ ├── controller │ │ │ └── AuthController.java │ │ ├── model │ │ │ └── User.java │ │ ├── service │ │ │ └── JwtUtil.java │ │ └── filter │ │ └── JwtRequestFilter.java │ └── resources │ └── application.properties └── test
二、依赖配置
在pom.xml中添加必要的依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <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> </dependencies>
三、用户模型
创建一个简单的用户模型:
package com.example.jwt.model; public class User { private String username; private String password; // Constructors, getters, and setters //也可以使用Lombok public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public String getPassword() { return password; } }
四、JWT工具类
创建JWT工具类,负责生成和解析JWT:
package com.example.jwt.service; 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; /** *Jwt工具类 */ @Component//加入Spring容器 public class JwtUtil { private String secret = "your_secret_key"; // 强密码 private long expiration = 60 * 60 * 1000; // 1小时 //这个方法用于生成 JWT。它接受用户名作为参数。 public String generateToken(String username) { Map<String, Object> claims = new HashMap<>(); return createToken(claims, username); } //私有方法,用于实际生成 JWT private String createToken(Map<String, Object> claims, String subject) { return Jwts.builder()//开始构建 JWT 的构建器 .setClaims(claims)//设置 JWT 中的声明 .setSubject(subject)//设置主题(通常是用户名) .setIssuedAt(new Date(System.currentTimeMillis()))//设置 JWT 的签发时间 .setExpiration(new Date(System.currentTimeMillis() + expiration))//设置 JWT 的过期时间 .signWith(SignatureAlgorithm.HS256, secret)//使用指定的算法(HS256)和密钥对 JWT 进行签名 .compact();//生成最终的 JWT 字符串 } //用于验证给定的 JWT 是否有效。 public Boolean validateToken(String token, String username) { final String extractedUsername = extractUsername(token);//提取 JWT 中的用户名 return (extractedUsername.equals(username) && !isTokenExpired(token));//检查提取的用户名与提供的用户名是否匹配,并且检查 JWT 是否未过期 } //从 JWT 中提取用户名 public String extractUsername(String token) { return extractAllClaims(token).getSubject(); } //解析 JWT 并返回所有声明 private Claims extractAllClaims(String token) { return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); }//使用密钥解析 JWT 获取其主体部分(声明) //检查 JWT 是否已过期 private Boolean isTokenExpired(String token) { return extractAllClaims(token).getExpiration().before(new Date()); } }
五、JWT请求过滤器
创建JWT请求过滤器,用于拦截请求并验证JWT:
package com.example.jwt.filter; import com.example.jwt.service.JwtUtil; 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.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component // 将该类标记为 Spring 组件,以便自动扫描和管理 public class JwtRequestFilter extends OncePerRequestFilter { @Autowired // 自动注入 JwtUtil 实例 private JwtUtil jwtUtil; @Autowired // 自动注入 UserDetailsService 实例 private UserDetailsService userDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { // 从请求中获取 Authorization 头部 final String authorizationHeader = request.getHeader("Authorization"); String username = null; // 初始化用户名 String jwt = null; // 初始化 JWT 令牌 // 检查 Authorization 头部是否存在且以 "Bearer " 开头 if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { // 提取 JWT 令牌(去掉 "Bearer " 前缀) jwt = authorizationHeader.substring(7); // 从 JWT 中提取用户名 username = jwtUtil.extractUsername(jwt); } // 如果用户名不为空且当前 SecurityContext 没有身份验证信息 if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { // 根据用户名加载用户详细信息 UserDetails userDetails = userDetailsService.loadUserByUsername(username); // 验证 JWT 是否有效 if (jwtUtil.validateToken(jwt, userDetails.getUsername())) { // 创建身份验证令牌,并设置用户的权限 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); // 设置请求的详细信息 authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); // 将身份验证信息存入 SecurityContext SecurityContextHolder.getContext().setAuthentication(authenticationToken); } } // 继续过滤器链 chain.doFilter(request, response); } }
六、安全配置
配置Spring Security,以保护API并使用JWT:
package com.example.jwt.config; import com.example.jwt.filter.JwtRequestFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 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.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtRequestFilter jwtRequestFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/auth/login").permitAll() // 公开登录接口 .anyRequest().authenticated() // 其他接口需要认证 .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 无状态会话 // 添加JWT过滤器 http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user").password(passwordEncoder().encode("password")).roles("USER"); // 示例用户 } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
七、身份验证控制器
创建一个控制器来处理登录请求并返回JWT:
package com.example.jwt.controller; import com.example.jwt.model.User; import com.example.jwt.service.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/auth") public class AuthController { @Autowired private JwtUtil jwtUtil; @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @PostMapping("/login") public String login(@RequestBody User user) { try { authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()) ); } catch (Exception e) { throw new RuntimeException("Invalid credentials"); } final UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUsername()); return jwtUtil.generateToken(userDetails.getUsername()); } }
八、测试JWT
- 启动Spring Boot应用程序。
- 使用Postman或其他工具测试登录接口。
请求示例:
POST /auth/login Content-Type: application/json { "username": "user", "password": "password" }
响应示例:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5c..." }
- 使用返回的token访问受保护的资源:
GET /protected/resource Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5c...
总结
到此这篇关于Java中JWT(JSON Web Token)运用的文章就介绍到这了,更多相关Java中JWT的运用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
SpringBoot+Redis执行lua脚本的5种方式总结
Lua是一种快速、轻量级的脚本语言,广泛应用于各种领域,包括数据库,Redis作为一个内嵌Lua解释器的NoSQL数据库,允许通过Lua脚本在服务器端执行一些复杂的操作,本文给大家介绍了使用SpringBoot Redis执行lua脚本的五种方式,需要的朋友可以参考下2023-11-11
最新评论