SpringBoot安全三剑客:Security+JWT+OAuth2全流程实现

🎓博主介绍:Java、Python、js全栈开发 “多面手”,精通多种编程语言和技术,痴迷于人工智能领域。秉持着对技术的热爱与执着,持续探索创新,愿在此分享交流和学习,与大家共进步。
📖全栈开发环境搭建运行攻略:多语言一站式指南(环境搭建+运行+调试+发布+保姆级详解)
👉感兴趣的可以先收藏起来,希望帮助更多的人
在这里插入图片描述

SpringBoot安全三剑客:Security+JWT+OAuth2全流程实现

一、引言

在当今的Web应用开发中,安全性是至关重要的一环。Spring Boot作为一款广泛使用的开发框架,为开发者提供了便捷的开发体验。而Spring Security、JWT(JSON Web Token)和OAuth2这三个技术,被称为Spring Boot安全三剑客,它们结合起来可以为Spring Boot应用提供全面、高效且安全的认证与授权解决方案。本文将详细介绍如何在Spring Boot应用中全流程实现这三个技术的整合。

二、Spring Security基础

2.1 Spring Security简介

Spring Security是一个强大且高度可定制的身份验证和访问控制框架,是Spring生态系统中的重要组成部分。它提供了全面的安全服务,包括基于表单的认证、HTTP基本认证、OAuth2等多种认证方式,以及基于角色的访问控制。

2.2 Spring Security在Spring Boot中的集成

在Spring Boot项目中集成Spring Security非常简单,只需要在pom.xml中添加相应的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

添加依赖后,Spring Security会自动为应用添加基本的安全配置,所有的HTTP请求都需要进行身份验证。

2.3 自定义Spring Security配置

可以通过创建一个继承自WebSecurityConfigurerAdapter的配置类来自定义Spring Security的配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
           .authorizeRequests()
               .antMatchers("/public/**").permitAll()
               .anyRequest().authenticated()
               .and()
           .formLogin()
               .and()
           .httpBasic();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

在上述配置中,/public/**路径下的请求不需要进行身份验证,其他请求则需要进行身份验证。同时,配置了表单登录和HTTP基本认证方式。

三、JWT基础

3.1 JWT简介

JWT(JSON Web Token)是一种用于在网络应用间安全传输信息的开放标准(RFC 7519)。它通常由三部分组成:头部(Header)、负载(Payload)和签名(Signature)。JWT以JSON对象的形式存储信息,并通过签名进行验证,确保信息的完整性和真实性。

3.2 JWT的工作原理

  1. 用户登录成功后,服务器生成一个JWT,并将其返回给客户端。
  2. 客户端在后续的请求中,将JWT包含在请求头中发送给服务器。
  3. 服务器接收到请求后,验证JWT的签名和有效性,如果验证通过,则允许用户访问受保护的资源。

3.3 在Spring Boot中集成JWT

首先,在pom.xml中添加JWT相关的依赖:

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

然后,创建一个JWT工具类来生成和验证JWT:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

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

@Component
public class JwtUtils {

    private static final String SECRET_KEY = "your_secret_key";
    private static final long EXPIRATION_TIME = 86400000; // 24 hours

    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        return Jwts.builder()
               .setClaims(claims)
               .setSubject(userDetails.getUsername())
               .setIssuedAt(new Date(System.currentTimeMillis()))
               .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
               .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
               .compact();
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }

    public String extractUsername(String token) {
        return extractClaims(token).getSubject();
    }

    private Claims extractClaims(String token) {
        return Jwts.parser()
               .setSigningKey(SECRET_KEY)
               .parseClaimsJws(token)
               .getBody();
    }

    private Boolean isTokenExpired(String token) {
        final Date expiration = extractClaims(token).getExpiration();
        return expiration.before(new Date());
    }
}

最后,在Spring Security配置中添加JWT过滤器:

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.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;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
           .csrf().disable()
           .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
               .and()
           .authorizeRequests()
               .antMatchers("/public/**").permitAll()
               .anyRequest().authenticated()
               .and()
           .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

JWT过滤器的实现如下:

import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        final String requestTokenHeader = request.getHeader("Authorization");

        String username = null;
        String jwtToken = null;

        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = jwtUtils.extractUsername(jwtToken);
            } catch (IllegalArgumentException e) {
                System.out.println("Unable to get JWT Token");
            } catch (ExpiredJwtException e) {
                System.out.println("JWT Token has expired");
            }
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

            if (jwtUtils.validateToken(jwtToken, userDetails)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                       .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        filterChain.doFilter(request, response);
    }
}

四、OAuth2基础

4.1 OAuth2简介

OAuth2是一种开放标准的授权协议,用于允许第三方应用代表用户访问受保护的资源。它提供了一种安全的方式,让用户可以授权第三方应用访问其在另一个服务提供商上的资源,而无需将自己的用户名和密码提供给第三方应用。

4.2 OAuth2的工作流程

OAuth2的工作流程主要包括以下几个步骤:

  1. 用户请求访问第三方应用的受保护资源。
  2. 第三方应用将用户重定向到授权服务器,请求用户授权。
  3. 用户在授权服务器上登录并授权第三方应用访问其资源。
  4. 授权服务器返回授权码给第三方应用。
  5. 第三方应用使用授权码向授权服务器换取访问令牌。
  6. 第三方应用使用访问令牌访问资源服务器上的受保护资源。

4.3 在Spring Boot中集成OAuth2

pom.xml中添加OAuth2相关的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

然后,在application.properties中配置OAuth2客户端信息:

spring.security.oauth2.client.registration.google.client-id=your_client_id
spring.security.oauth2.client.registration.google.client-secret=your_client_secret
spring.security.oauth2.client.registration.google.scope=openid,profile,email
spring.security.oauth2.client.provider.google.authorization-uri=https://accounts.google.com/o/oauth2/v2/auth
spring.security.oauth2.client.provider.google.token-uri=https://www.googleapis.com/oauth2/v4/token
spring.security.oauth2.client.provider.google.user-info-uri=https://www.googleapis.com/oauth2/v3/userinfo
spring.security.oauth2.client.provider.google.user-name-attribute=name

最后,在Spring Security配置中添加OAuth2登录支持:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.web.authentication.LoginUrlAuthenticationEntryPoint;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
           .authorizeRequests()
               .antMatchers("/public/**").permitAll()
               .anyRequest().authenticated()
               .and()
           .oauth2Login()
               .and()
           .exceptionHandling()
               .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/oauth2/authorization/google"));
    }
}

五、Spring Boot安全三剑客的整合

5.1 整体架构设计

将Spring Security、JWT和OAuth2整合在一起,可以构建一个强大的安全架构。Spring Security负责整体的安全配置和访问控制,JWT用于在客户端和服务器之间安全传输用户信息,OAuth2用于第三方应用的授权登录。

5.2 实现步骤

  1. 配置Spring Security,包括基本的认证和授权规则。
  2. 集成JWT,实现JWT的生成、验证和过滤。
  3. 集成OAuth2,配置OAuth2客户端信息和登录支持。
  4. 在控制器中处理不同的认证和授权逻辑。

5.3 示例代码

以下是一个简单的控制器示例,演示了如何处理不同的认证和授权逻辑:

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/public")
    public String publicEndpoint() {
        return "This is a public endpoint.";
    }

    @GetMapping("/protected")
    @PreAuthorize("hasRole('USER')")
    public String protectedEndpoint() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return "Hello, " + authentication.getName() + "! This is a protected endpoint.";
    }
}

六、总结

通过Spring Security、JWT和OAuth2的整合,我们可以为Spring Boot应用提供全面、高效且安全的认证与授权解决方案。Spring Security提供了强大的安全配置和访问控制功能,JWT确保了用户信息的安全传输,OAuth2支持第三方应用的授权登录。在实际开发中,可以根据具体需求对这些技术进行灵活配置和扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

fanxbl957

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

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

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

打赏作者

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

抵扣说明:

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

余额充值