Spring Boot 如何使用 JWT 进行认证和授权

简介: Spring Boot 如何使用 JWT 进行认证和授权

Spring Boot 如何使用 JWT 进行认证和授权


JSON Web Token(JWT)是一种用于安全地传输信息的开放标准。JWT 是一种轻量级的身份验证和授权机制,可以在客户端和服务器之间安全地传输信息。在本文中,我们将介绍如何在 Spring Boot 应用程序中使用 JWT 进行认证和授权。


7c895a956bdaa171a48a52c351952e23_646274175db34aa587ca0a9101c1acbc.png


JWT 概述


JWT 是一种基于 JSON 的开放标准,用于在客户端和服务器之间安全地传输信息。JWT 由三部分组成:Header、Payload 和 Signature。


Header


Header 通常由两部分组成:token 类型和算法。例如,以下是一个 JWT Header 的示例:


{
  "alg": "HS256",
  "typ": "JWT"
}


在上面的示例中,alg 表示使用的算法,typ 表示 token 的类型。


Payload


Payload 包含要传输的信息。Payload 通常由一些标准字段和自定义字段组成。例如,以下是一个 JWT Payload 的示例:


{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}


在上面的示例中,sub 表示主题,name 表示名称,iat 表示 token 的创建时间。


Signature


Signature 用于验证 token 的真实性和完整性。Signature 由 Header、Payload 和一个密钥组成,可以使用算法对它们进行签名。例如,以下是一个 JWT Signature 的示例:


HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)


在上面的示例中,secret 表示密钥。


JWT 认证和授权


在 Spring Boot 应用程序中,我们可以使用 JWT 实现身份验证和授权。通常,我们需要实现以下步骤:


  1. 客户端通过用户名和密码进行身份验证。
  2. 服务器生成 JWT 并将其发送给客户端。
  3. 客户端将 JWT 存储在本地。
  4. 客户端向服务器发送请求时,在请求头中添加 JWT。
  5. 服务器验证 JWT,并根据 JWT 中的信息授权。


下面是一个示例 Spring Boot 应用程序,用于实现 JWT 认证和授权。


添加依赖

首先,我们需要在 pom.xml 文件中添加以下依赖:


<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>


创建实体类


我们需要创建一个 User 类来表示用户信息。例如,以下是一个 User 类的示例:


public class User {
    private String username;
    private String password;
    public User() {}
    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;
    }
}


创建认证接口


我们需要创建一个认证接口来处理用户身份验证请求。例如,以下是一个 AuthController 类的示例:


@RestController
@RequestMapping("/auth")
public class AuthController {
    private final AuthenticationManager authenticationManager;
    private final JwtUtils jwtUtils;
    public AuthController(AuthenticationManager authenticationManager, JwtUtils jwtUtils) {
        this.authenticationManager = authenticationManager        ;
        this.jwtUtils = jwtUtils;
    }
    @PostMapping("/login")
    public ResponseEntity<?> authenticateUser(@RequestBody User user) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String jwt = jwtUtils.generateJwtToken(authentication);
        return ResponseEntity.ok(new JwtResponse(jwt));
    }
}

在上面的示例中,我们使用 @RestController 和 @RequestMapping 注解创建了一个名为 AuthController 的类。我们使用 @PostMapping 和 @RequestBody 注解创建了一个名为 authenticateUser 的方法,用于处理用户身份验证请求。在该方法中,我们使用 AuthenticationManager 对象进行身份验证,并使用 JwtUtils 对象生成 JWT。


创建 JWT 工具类


我们需要创建一个 JwtUtils 类来生成和验证 JWT。例如,以下是一个 JwtUtils 类的示例:


@Component
public class JwtUtils {
    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private int expiration;
    public String generateJwtToken(Authentication authentication) {
        UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
        return Jwts.builder()
                .setSubject((userPrincipal.getUsername()))
                .setIssuedAt(new Date())
                .setExpiration(new Date((new Date()).getTime() + expiration * 1000))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }
    public boolean validateJwtToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(secret).parseClaimsJws(authToken);
            return true;
        } catch (SignatureException e) {
            logger.error("Invalid JWT signature: {}", e.getMessage());
        } catch (MalformedJwtException e) {
            logger.error("Invalid JWT token: {}", e.getMessage());
        } catch (ExpiredJwtException e) {
            logger.error("JWT token is expired: {}", e.getMessage());
        } catch (UnsupportedJwtException e) {
            logger.error("JWT token is unsupported: {}", e.getMessage());
        } catch (IllegalArgumentException e) {
            logger.error("JWT claims string is empty: {}", e.getMessage());
        }
        return false;
    }
    public String getUsernameFromJwtToken(String token) {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody().getSubject();
    }
}

在上面的示例中,我们使用 @Component 注解创建了一个名为 JwtUtils 的类。我们使用 @Value 注解获取 JWT 密钥和过期时间。我们使用 Jwts.builder() 方法创建一个 JWT,并使用 setSubject()、setIssuedAt() 和 setExpiration() 方法设置 JWT 的主题、创建时间和过期时间。我们使用 signWith() 方法和 HS512 算法对 JWT 进行签名,并使用 compact() 方法生成 JWT。我们使用 Jwts.parser() 方法验证 JWT,并使用 parseClaimsJws() 方法获取 JWT 中的主题。我们使用各种异常处理机制来处理 JWT 验证过程中可能出现的异常。


创建授权拦截器


我们需要创建一个授权拦截器来验证请求中的 JWT。例如,以下是一个 JwtAuthTokenFilter 类的示例:


public class JwtAuthTokenFilter extends OncePerRequestFilter {
    private final JwtUtils jwtUtils;
    public JwtAuthTokenFilter(JwtUtils jwtUtils) {
        this.jwtUtils = jwtUtils;
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            String jwt = parseJwt(request);
            if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
                String username = jwtUtils.getUsernameFromJwtToken(jwt);
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception e) {
            logger.error("Cannot set user authentication: {}", e.getMessage());
        }
        filterChain.doFilter(request, response);
    }
    private String parseJwt(HttpServletRequest request) {
        String headerAuth = request.getHeader("Authorization");
        if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
            return headerAuth.substring(7, headerAuth.length());
        }
        return null;
    }
}

在上面的示例中,我们使用 OncePerRequestFilter 类创建了一个名为 JwtAuthTokenFilter 的拦截器。在 doFilterInternal() 方法中,我们使用 parseJwt() 方法获取请求头中的 JWT,并使用 JwtUtils 类中的 validateJwtToken() 方法验证 JWT。如果 JWT 验证成功,我们使用 getUsernameFromJwtToken() 方法获取 JWT 中的用户名,并使用 userDetailsService 加载用户详细信息。我们使用 UsernamePasswordAuthenticationToken 对象创建一个新的身份验证对象,并使用 SecurityContextHolder 将其设置为当前身份验证对象。最后,我们调用 filterChain.doFilter() 方法将请求传递给下一个过滤器。


配置 Spring Security


我们需要在 Spring Security 配置中添加 JwtAuthTokenFilter 来验证 JWT。例如,以下是一个 SecurityConfiguration 类的示例:


@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private JwtUtils jwtUtils;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
                .antMatchers("/auth/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(new JwtAuthTokenFilter(jwtUtils), UsernamePasswordAuthenticationFilter.class);
    }
    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

在上面的示例中,我们使用 @Configuration 和 @EnableWebSecurity 注解创建了一个名为 SecurityConfiguration 的类。我们使用 @Autowired 注解注入了一个名为 userDetailsService 的 UserDetailsServiceImpl 对象和一个名为 jwtUtils 的 JwtUtils 对象。我们使用 configure() 方法配置了 HTTP 安全性,并使用 antMatchers() 方法指定不需要身份验证的 URL。我们使用 addFilterBefore() 方法添加了 JwtAuthTokenFilter 来验证 JWT。我们使用 configureAuthentication() 方法配置了身份验证管理器,并使用 passwordEncoder() 方法创建了一个密码编码器。我们使用 authenticationManagerBean() 方法创建了一个身份验证管理器。


创建响应类


最后,我们需要创建一个 JwtResponse 类来表示 JWT 响应。例如,以下是一个 JwtResponse 类的示例:


public class JwtResponse {
    private final String jwt;
    public JwtResponse(String jwt) {
        this.jwt = jwt;
    }
    public String getJwt() {
        return jwt;
    }
}


结论


在本文中,我们介绍了如何在 Spring Boot 应用程序中使用 JWT 进行身份验证和授权。我们创建了一个 User 类来表示用户信息,创建了一个 AuthController 类来处理用户身份验证请求,创建了一个 JwtUtils 类来生成和验证 JWT,创建了一个 JwtAuthTokenFilter 类来验证请求中的 JWT,创建了一个 SecurityConfiguration 类来配置 Spring Security,创建了一个 JwtResponse 类来表示 JWT 响应。我们希望本文能够帮助您理解如何在 Spring Boot 应用程序中使用 JWT 进行身份验证和授权。


相关文章
Spring Boot 实现通用 Auth 认证的 4 种方式
本文介绍了在Spring Boot中实现通用Auth的四种方式:传统AOP、拦截器(Interceptor)、参数解析器(ArgumentResolver)和过滤器(Filter)。每种方式都通过实例代码详细说明了实现步骤,并总结了它们的执行顺序。首先,Filter作为Servlet规范的一部分最先被调用;接着是Interceptor,它可以在Controller方法执行前后进行处理;然后是ArgumentResolver,在参数传递给Controller之前解析并验证参数
SpringBoot集成Shiro权限+Jwt认证
本文主要描述如何快速基于SpringBoot 2.5.X版本集成Shiro+JWT框架,让大家快速实现无状态登陆和接口权限认证主体框架,具体业务细节未实现,大家按照实际项目补充。
133 11
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
695 12
什么是JWT?如何使用Spring Boot Security实现它?
什么是JWT?如何使用Spring Boot Security实现它?
648 5
|
4月前
|
Spring Boot 应用如何实现 JWT 认证?
Spring Boot 应用如何实现 JWT 认证?
122 8
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
108 0
基于Springboot实现专业认证材料管理系统
该知识产权服务平台系统项目采用mvc设计模式, 其中知识产权服务平台系统的视图与知识产权服务平台系统业务逻辑进行了分层设计, 特别方便后续知识产权服务平台系统系统的开发 设计这种mvc的架构的好处是完全的可以将业务进行分层, 进行高内聚低耦合, 分为service层, dao层, controller层, 架构清晰 本项目主要基于Springboot 和ruoyi来开发一套专业认证材料管理系统,对各专业相关的文档材料进行管理,主要包含的功能模块有: 系统管理:用户管理、角色管理、菜单管理、操作日志 业务模块:专业管理、认证材料管理、相关网站管理
198 0
基于Springboot实现专业认证材料管理系统
基于SpringBoot+Vue实现的留守儿童爱心网站设计与实现(计算机毕设项目实战+源码+文档)
博主是一位全网粉丝超过100万的CSDN特邀作者、博客专家,专注于Java、Python、PHP等技术领域。提供SpringBoot、Vue、HTML、Uniapp、PHP、Python、NodeJS、爬虫、数据可视化等技术服务,涵盖免费选题、功能设计、开题报告、论文辅导、答辩PPT等。系统采用SpringBoot后端框架和Vue前端框架,确保高效开发与良好用户体验。所有代码由博主亲自开发,并提供全程录音录屏讲解服务,保障学习效果。欢迎点赞、收藏、关注、评论,获取更多精品案例源码。
基于SpringBoot+Vue实现的家政服务管理平台设计与实现(计算机毕设项目实战+源码+文档)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
基于SpringBoot+Vue实现的家乡特色推荐系统设计与实现(源码+文档+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!