spring boot3登录开发-整合jwt

⛰️个人主页:     蒾酒

🔥系列专栏:《spring boot实战》


目录

前置条件

jwt简介

导依赖

编写jwt工具类

1.配置项直接嵌入代码,通过类名.静态方法使用

2.配置项写到application.yml,交由spring容器管理依赖注入使用

写在最后


前置条件

已经初始化好一个spring boot项目且版本为3X,项目可正常启动。

作者版本为3.2.2

初始化教程:

新版idea创建spring boot项目-CSDN博客文章浏览阅读2.5k次,点赞60次,收藏66次。本教程对新手小白友好。若根据教程创建出现问题导致失败可下载我提供的源码,在文章最后。本教程较新本文使用的工具以及搭建的springboot版本都是很新版本:idea版本如下spring boot 版本如下:本教程使用的是汉化后的idea。https://blog.csdn.net/qq_62262918/article/details/135785412?spm=1001.2014.3001.5501

jwt简介

  1. JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用间传输和存储信息的一种安全方式。
  2. 它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
  3. JWT可以被用作身份验证和授权,通过在服务器和客户端之间传递令牌来验证用户的身份并允许访问受保护的资源。
  4. 由于JWT是基于数字签名的,所以可以确保数据的完整性和安全性。它的设计简单、易于实现,并且可以跨不同的平台和语言使用。

导依赖

pom.xml:

 <dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.9.1</version>
 </dependency>
<!-- 如果jdk大于1.8,则还需导入下面依赖-->
 <dependency>
     <groupId>javax.xml.bind</groupId>
     <artifactId>jaxb-api</artifactId>
     <version>2.3.1</version>
 </dependency>

注意:你的jdk版本如果为1.8导入第一个就行,大于1.8就要导入两个。

编写jwt工具类

JWT(JSON Web Token)工具类在实际开发中通常包含以下一些常用方法:

  1. 生成JWT:用于生成JWT令牌并返回令牌字符串。
  2. 解析JWT:用于解析JWT令牌,验证签名,并获取其中的声明信息。
  3. 验证JWT:用于验证JWT的有效性,包括验证签名、过期时间等。
  4. 刷新JWT:用户还在操作,马上要快过期时,延长其有效期(无感刷新)。
  5. 其他辅助方法:例如获取JWT中的特定声明信息,验证JWT是否包含某个声明,等等。

其中生成和解析token是必须的,其他方法根据项目需求设计来决定写不写。

1.配置项直接嵌入代码,通过类名.静态方法使用

jwt工具类如下:

上面五种常用方法已经写好,cv过来直接能用。按需修改也可以。

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;


/**
 * @author mijiupro
 */
public class JwtUtils {

    private static final String SIGN_KEY = "mijiu";// 加密密钥

    private static final long EXPIRE_TIME = 12 * 60 * 60 * 1000; //到期时间,12小时,单位毫秒
    private static final byte[] SECRET_KEY = SIGN_KEY.getBytes(StandardCharsets.UTF_8);

    /**
     * 生成token令牌
     * @param claims JWT第二部分负载 payload 中存储的内容
     * @param subject 主题(用户类型)
     * @return token
     */
    public static String generateToken(Map<String,Object> claims, String subject) {
        return Jwts.builder()
                .setId(Claims.ID)//设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为令牌的唯一标识。
                .setSubject("mijiu")//设置主题,一般为用户类型
                .setIssuedAt(new Date())//设置签发时间
                .addClaims(claims)//设置负载
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)//设置签名算法
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))//设置令牌过期时间
                .compact();//生成令牌
    }

    /**
     * 解析token令牌
     * @param token token令牌
     * @return 负载
     */
    public static Claims parseToken(String token) {

        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     *  验证token令牌
     * @param token 令牌
     * @return 是否有效
     */
    public static boolean validateToken(String token) {
        try {
            Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 刷新Token
     * @param token 旧的Token令牌
     * @return 新的Token令牌
     */
    public static String refreshToken(String token) {
        try {
            // 解析旧的Token,获取负载信息
            Claims claims = parseToken(token);
            // 生成新的Token,设置过期时间和签名算法等参数
            return generateToken(claims, claims.getSubject());
        } catch (Exception e) {
            throw new RuntimeException("无法刷新令牌!", e);
        }
    }


    /**
     * 从令牌中获取主题信息
     * @param token 令牌
     * @return 主题信息(用户类型)
     */
    public static String getSubjectFromToken(String token) {
        try {
            Claims claims = parseToken(token); // 解析令牌,获取负载信息
            return claims.getSubject(); // 返回主题信息
        } catch (Exception e) {
            throw new RuntimeException("无法从令牌中获取主题。", e);
        }
    }

}

编写测试

测试代码如下:

import com.mijiu.commom.util.JwtUtils;
import io.jsonwebtoken.Claims;
import org.junit.jupiter.api.Test;

import java.util.Map;

public class JwtTest {

    @Test
    public void testJwt() {
        // 设置JWT的payload
    Map<String, Object> claims = Map.of("username", "mijiu", "role", "admin");

        // 生成JWT
        String jwt = JwtUtils.generateToken(claims, "secret");

        System.out.println("JWT: " + jwt);

        // 解析JWT
        Claims claims1 = JwtUtils.parseToken(jwt);

        // 获取完整的payload
        String payload = claims1.toString();
        System.out.println("Payload: " + payload);
    }
}

作者目录结构

​​

运行测试代码

​​测试通过

2.配置项写到application.yml,交由spring容器管理依赖注入使用

jwt工具类如下:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;


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


/**
 * @author mijiupro
 */
@Data
@Component
@ConfigurationProperties(prefix = "jwt")
public class JwtUtils {

    private String secret;//密钥
    private  long expiration;//过期时间


    /**
     * 生成token令牌
     * @param claims JWT第二部分负载 payload 中存储的内容
     * @param subject 主题(用户类型)
     * @return token
     */
    public  String generateToken(Map<String,Object> claims, String subject) {
        return Jwts.builder()
                .setId(Claims.ID)//设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为令牌的唯一标识。
                .setSubject("mijiu")//设置主题,一般为用户类型
                .setIssuedAt(new Date())//设置签发时间
                .addClaims(claims)//设置负载
                .signWith(SignatureAlgorithm.HS256, secret)//设置签名算法
                .setExpiration(new Date(System.currentTimeMillis() + expiration))//设置令牌过期时间
                .compact();//生成令牌
    }

    /**
     * 解析token令牌
     * @param token token令牌
     * @return 负载
     */
    public  Claims parseToken(String token) {

        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     *  验证token令牌
     * @param token 令牌
     * @return 是否有效
     */
    public  boolean validateToken(String token) {
        try {
            Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 刷新Token
     * @param token 旧的Token令牌
     * @return 新的Token令牌
     */
    public  String refreshToken(String token) {
        try {
            // 解析旧的Token,获取负载信息
            Claims claims = parseToken(token);
            // 生成新的Token,设置过期时间和签名算法等参数
            return generateToken(claims, claims.getSubject());
        } catch (Exception e) {
            throw new RuntimeException("无法刷新令牌!", e);
        }
    }


    /**
     * 从令牌中获取主题信息
     * @param token 令牌
     * @return 主题信息(用户类型)
     */
    public  String getSubjectFromToken(String token) {
        try {
            Claims claims = parseToken(token); // 解析令牌,获取负载信息
            return claims.getSubject(); // 返回主题信息
        } catch (Exception e) {
            throw new RuntimeException("无法从令牌中获取主题。", e);
        }
    }

}
注意:此代码用到了lombok的@Data注解,来添加getter 和 setter 方法,请确保有该依赖

依赖坐标:
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

配置文件添加jwt的配置项

application.yml:

jwt:
  secret: 123456 #密钥
  expiration: 43200000 #过期时间 12h

​​

编写测试类

import com.mijiu.commom.util.JwtUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * @author mijiupro
 */


@RestController
@RequestMapping("/test")
public class TestController {
    private final JwtUtils jwtUtils;
    public TestController(JwtUtils jwtUtils) {
        this.jwtUtils = jwtUtils;
    }

    @GetMapping("/get-token")
    public String getToken() {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", "mijiu");
        claims.put("role", "admin");
        return jwtUtils.generateToken(claims,"user");
    }
    @GetMapping("/parse-token/{token}")
    public  String parseToken(@PathVariable String token) {
        return jwtUtils.parseToken(token).toString();

    }
}

目录结构

​​

启动项目

请求jwt测试接口

生成token接口:

​​

复制token

请求解析token接口并路径传参传入复制的token

​​

测试成功。

写在最后

项目模板已开源。

开源地址:
springboot3x-template: 本项目为单体架构spring boot3x版本的web后端服务开发模板,整合常用依赖,以及起步功能,适合中作为小项目的工程初始化脚手架。大幅度提高开发效率。 (gitee.com)icon-default.png?t=N7T8https://gitee.com/mi9688-wine/springboot-template

欢迎star任何问题评论区或私信讨论,欢迎指正。

  • 126
    点赞
  • 158
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
以下是Spring Boot集成Spring Security、JWT和OAuth2的示例代码: 1. 添加依赖 在pom.xml文件中添加以下依赖: ```xml <!-- Spring Security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- Spring Security OAuth2 --> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.3.7.RELEASE</version> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> ``` 2. 配置Spring Security 在Spring Boot应用程序中,可以通过配置类来配置Spring Security。创建一个配置类,命名为SecurityConfig.java,并添加以下内容: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests().antMatchers("/oauth/**").permitAll() .anyRequest().authenticated() .and().formLogin().permitAll(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } } ``` 这个类配置了Spring Security,启用了Web安全性,并定义了一个UserDetailsService实例,该实例将用于验证用户。 3. 配置OAuth2 创建一个OAuth2配置类,命名为OAuth2Config.java,并添加以下内容: ```java @Configuration @EnableAuthorizationServer public class OAuth2Config extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private DataSource dataSource; @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.jdbc(dataSource); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager) .userDetailsService(userDetailsService) .accessTokenConverter(accessTokenConverter()); } @Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); } @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("secret"); return converter; } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()"); } @Bean public ClientDetailsService clientDetailsService() { return new JdbcClientDetailsService(dataSource); } @Bean public ApprovalStore approvalStore() { return new JdbcApprovalStore(dataSource); } } ``` 这个类配置了OAuth2服务端,启用了授权服务器,并定义了一个客户端详情服务实例,该实例将用于管理客户端的详细信息。它还定义了一个令牌存储实例,该实例将用于存储访问令牌。 4. 配置JWT 创建一个JWT配置类,命名为JwtConfig.java,并添加以下内容: ```java @Configuration public class JwtConfig { @Value("${jwt.secret}") private String secret; @Bean public Key key() { return Keys.hmacShaKeyFor(secret.getBytes()); } @Bean public JwtDecoder jwtDecoder() { return NimbusJwtDecoder.withSecretKey(key()).build(); } @Bean public JwtEncoder jwtEncoder() { return NimbusJwtEncoder.withSecretKey(key()).build(); } } ``` 这个类配置了JWT,定义了一个秘钥,该秘钥将用于签署和验证JWT令牌。 5. 配置资源服务器 创建一个资源服务器配置类,命名为ResourceServerConfig.java,并添加以下内容: ```java @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Autowired private JwtAccessTokenConverter accessTokenConverter; @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/api/**").authenticated() .anyRequest().permitAll(); } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.tokenStore(tokenStore()).accessTokenConverter(accessTokenConverter); } @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter); } } ``` 这个类配置了资源服务器,启用了资源服务器,并定义了一个令牌存储实例,该实例将用于存储访问令牌。 6. 创建实体类 创建一个User实体类,命名为User.java,并添加以下内容: ```java @Entity @Table(name = "users") public class User implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(unique = true) private String username; private String password; @ElementCollection(fetch = FetchType.EAGER) private List<String> roles; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } } ``` 这个类定义了一个用户实体,实现了UserDetails接口,该接口提供了有关用户的详细信息。 7. 创建数据访问对象 创建一个UserRepository接口,命名为UserRepository.java,并继承JpaRepository接口,添加以下内容: ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByUsername(String username); } ``` 这个接口定义了一个用户数据访问对象,用于管理用户。 8. 实现用户服务 创建一个UserServiceImpl类,命名为UserServiceImpl.java,并添加以下内容: ```java @Service public class UserServiceImpl implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found")); } } ``` 这个类实现了UserDetailsService接口,该接口提供了一个方法,根据用户名加载用户信息。 9. 创建控制器 创建一个UserController类,命名为UserController.java,并添加以下内容: ```java @RestController @RequestMapping("/api") public class UserController { @GetMapping("/users") public List<User> getUsers() { return userRepository.findAll(); } @PostMapping("/users") public User createUser(@RequestBody User user) { user.setPassword(passwordEncoder.encode(user.getPassword())); return userRepository.save(user); } @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; } ``` 这个类定义了一个RESTful API控制器,用于管理用户。 10. 测试 启动应用程序,并使用Postman测试API接口。例如,使用POST方法向/api/users端点发送请求,创建一个新用户。 这就是Spring Boot集成Spring Security、JWT和OAuth2的示例代码。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒾酒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值