当前位置:首页 » 《资源分享》 » 正文

Java中JWT(JSON Web Token)的运用

18 人参与  2024年10月19日 08:00  分类 : 《资源分享》  评论

点击全文阅读


目录

1. JWT的结构2. JWT的优点3. JWT的流转过程4.具体案例一、项目结构二、依赖配置三、用户模型四、JWT工具类五、JWT请求过滤器六、安全配置七、身份验证控制器八、测试JWT
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@EnableWebSecuritypublic 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/loginContent-Type: application/json{    "username": "user",    "password": "password"}

响应示例:

{    "token": "eyJhbGciOiJIUzI1NiIsInR5c..."}
使用返回的token访问受保护的资源:
GET /protected/resourceAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5c...

点击全文阅读


本文链接:http://zhangshiyu.com/post/173933.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1