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 进行身份验证和授权。


相关文章
|
1月前
|
安全 Java 数据库
安全无忧!在 Spring Boot 3.3 中轻松实现 TOTP 双因素认证
【10月更文挑战第8天】在现代应用程序开发中,安全性是一个不可忽视的重要环节。随着技术的发展,双因素认证(2FA)已经成为增强应用安全性的重要手段之一。本文将详细介绍如何在 Spring Boot 3.3 中实现基于时间的一次性密码(TOTP)双因素认证,让你的应用安全无忧。
100 5
|
1月前
|
JSON 安全 算法
|
1月前
|
JSON 安全 数据安全/隐私保护
Python认证新风尚:OAuth遇上JWT,安全界的时尚Icon👗
【10月更文挑战第2天】在当今互联网世界中,数据安全与隐私保护日益重要。Python 作为广泛应用于 Web 开发的语言,其认证机制也不断进化。OAuth 2.0 和 JSON Web Tokens (JWT) 成为当前最热门的安全认证方案,不仅保障数据安全传输,还简化了用户认证流程。本文将介绍 Python 如何结合 OAuth 2.0 和 JWT 打造安全高效的认证体系。
39 3
|
20天前
|
JSON 安全 数据安全/隐私保护
Python认证新风尚:OAuth遇上JWT,安全界的时尚Icon👗
在当今互联网世界中,数据安全和隐私保护至关重要。Python 作为 Web 开发的主流语言,其认证机制也在不断进步。OAuth 2.0 和 JSON Web Tokens (JWT) 是当前最热门的安全认证方案,不仅保障数据安全传输,还简化用户认证流程。本文介绍如何在 Python 中结合 OAuth 2.0 和 JWT,打造一套既安全又高效的认证体系。通过 Flask-HTTPAuth 和 PyJWT 等库,实现授权和验证功能,确保每次请求的安全性和便捷性。
32 3
|
1月前
|
安全 Java 关系型数据库
springboot整合springsecurity,从数据库中认证
本文介绍了如何在SpringBoot应用中整合Spring Security,并从数据库中进行用户认证的完整步骤,包括依赖配置、数据库表创建、用户实体和仓库接口、用户详情服务类、安全配置类、控制器类以及数据库初始化器的实现。
111 3
springboot整合springsecurity,从数据库中认证
|
1月前
|
存储 安全 Java
|
28天前
|
JSON 算法 安全
JWT Bearer 认证在 .NET Core 中的应用
【10月更文挑战第30天】JWT(JSON Web Token)是一种开放标准,用于在各方之间安全传输信息。它由头部、载荷和签名三部分组成,用于在用户和服务器之间传递声明。JWT Bearer 认证是一种基于令牌的认证方式,客户端在请求头中包含 JWT 令牌,服务器验证令牌的有效性后授权用户访问资源。在 .NET Core 中,通过安装 `Microsoft.AspNetCore.Authentication.JwtBearer` 包并配置认证服务,可以实现 JWT Bearer 认证。具体步骤包括安装 NuGet 包、配置认证服务、启用认证中间件、生成 JWT 令牌以及在控制器中使用认证信息
|
1月前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
1月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
31 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
21天前
|
JavaScript NoSQL Java
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 的前后端分离的后台管理系统
34 0
下一篇
无影云桌面