《Spring Security 简易速速上手小册》第1章 Spring Security 概述(2024 最新版)

在这里插入图片描述

文章目录

  • 1.1 Spring Security 的重要性
    • 1.1.1 基础知识详解
    • 1.1.2 主要案例:用户认证与授权
    • 1.1.3 拓展案例 1:OAuth2 社交登录
    • 1.1.4 拓展案例 2:JWT 认证
  • 1.2 Spring Security 的核心特性
    • 1.2.1 基础知识详解
    • 1.2.2 主要案例:基于角色的访问控制
    • 1.2.3 拓展案例 1:表单登录与数据库用户存储
    • 1.2.4 拓展案例 2:整合 OAuth2
  • 1.3 Spring Security 的发展历程
    • 1.3.1 基础知识详解
    • 1.3.2 主要案例:表达式驱动的安全性
    • 1.3.3 拓展案例 1:OAuth2 集成
    • 1.3.4 拓展案例 2:JWT 认证

1.1 Spring Security 的重要性

在这一节中,我们将首先深入探讨 Spring Security 的基础知识,然后通过三个实际案例,展示其在现实生产环境中的应用。这些案例将以 Java 为核心,展现 Spring Security 在保护应用程序方面的实用性。

1.1.1 基础知识详解

Spring Security 的重要性

在深入探讨 Spring Security 之前,让我们先了解为什么这个框架在现代 Web 应用开发中如此重要。

  1. 安全性的核心需求
    在数字时代,安全性是任何 Web 应用的基石。Spring Security 提供了一个健壮的安全框架,帮助开发者保护他们的应用免受各种网络攻击和安全威胁。

  2. 广泛的应用场景
    无论是小型企业应用还是大型企业级系统,Spring Security 都能灵活适应。它不仅支持传统的 Web 应用,还能很好地与微服务架构和云服务集成。

  3. 社区和支持
    作为 Spring 生态系统的一部分,Spring Security 拥有一个活跃的开发者社区和丰富的文档资源。这意味着它不断更新,能够应对新出现的安全挑战。

Spring Security 的核心概念

  1. 认证(Authentication)

    • 认证是确认某个实体的身份。在 Spring Security 中,这通常指验证用户名和密码,但也可以扩展到更复杂的方法,如多因素认证。
    • Spring Security 支持多种认证方式,如表单登录、LDAP、OAuth2 等。
  2. 授权(Authorization)

    • 授权涉及决定认证通过的实体可以访问哪些资源。简单来说,就是决定谁能做什么。
    • Spring Security 通过角色和权限来管理授权。它允许细粒度控制,比如基于方法的安全性。
  3. 防护措施

    • Spring Security 提供了多种防护措施来保护应用免受常见的网络攻击,例如跨站请求伪造(CSRF)和会话固定攻击。
    • 它还提供了其他高级功能,如安全通道(HTTPS 强制使用)和内容安全策略(CSP)。
  4. 过滤器链

    • Spring Security 使用一系列过滤器来处理安全相关的任务。这些过滤器在请求进入应用之前拦截请求,执行例如认证和授权的操作。
    • 了解这些过滤器及其顺序对于深入理解 Spring Security 的工作原理至关重要。

通过理解这些基础概念,开发者能够更好地利用 Spring Security 为他们的应用提供坚固的安全基础。下一步,我们将深入探讨如何在实际应用中实现这些概念,并通过具体案例加以展示。

1.1.2 主要案例:用户认证与授权

在这个案例中,我们将展示如何在一个 Spring Boot 应用程序中实现基本的用户认证和授权。这个案例将重点介绍如何配置 Spring Security 来管理用户登录,并根据用户角色授权访问特定资源。

案例 Demo

假设我们正在开发一个小型网站,该网站有两种类型的用户:普通用户和管理员。我们需要确保普通用户只能访问主页,而管理员则可以访问管理面板。

步骤 1:创建 Spring Boot 应用程序

首先,我们需要创建一个基本的 Spring Boot 应用程序。您可以使用 Spring Initializr(https://start.spring.io/)快速生成项目结构。

添加以下依赖:

  • Spring Web
  • Spring Security

步骤 2:配置 Spring Security

在我们的 Spring Boot 应用程序中,我们需要配置 Spring Security 来处理用户认证和授权。创建一个类继承自 WebSecurityConfigurerAdapter 并覆盖相应的方法。

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.WebSecurityConfigurerAdapter;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("{noop}password").roles("USER")
            .and()
            .withUser("admin").password("{noop}adminpass").roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/admin").hasRole("ADMIN")
                .antMatchers("/").hasAnyRole("USER", "ADMIN")
                .and()
            .formLogin();
    }
}

在这个配置中,我们定义了两个用户:一个普通用户和一个管理员,以及它们的权限。我们还启用了表单登录。

步骤 3:创建控制器

现在,我们需要创建一个简单的控制器来管理不同的页面。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MainController {

    @GetMapping("/")
    public String home() {
        return "home";
    }

    @GetMapping("/admin")
    public String admin() {
        return "admin";
    }
}

步骤 4:创建视图

为了完整性,我们还需要创建两个简单的 HTML 页面(home.htmladmin.html)来表示主页和管理页面。

步骤 5:运行和测试

运行您的 Spring Boot 应用程序,并访问 http://localhost:8080/。您应该会看到一个登录表单。使用不同的用户登录,并验证它们是否能正确访问对应的页面。

通过这个案例,您不仅能够了解如何在 Spring Security 中实现基本的认证和授权机制,还能够看到这些概念在实际应用中是如何工作的。这为您提供了一个坚实的基础,让您可以根据自己的需要进一步扩展和定制安全性配置。

1.1.3 拓展案例 1:OAuth2 社交登录

在这个案例中,我们将展示如何在 Spring Boot 应用中集成 OAuth2 社交登录,允许用户通过 Google 账户登录。这种方式提供了一种更便捷、安全的用户认证方法,同时提高了用户体验。

案例 Demo

假设我们的 Spring Boot 应用需要提供用户通过 Google 账户登录的功能。我们将使用 Spring Security 的 OAuth2 客户端支持来实现这一点。

步骤 1:添加相关依赖

首先,在你的 pom.xml 文件中添加以下依赖:

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

步骤 2:配置 OAuth2 登录

application.propertiesapplication.yml 文件中,添加 Google OAuth2 客户端配置:

spring.security.oauth2.client.registration.google.client-id=YOUR_GOOGLE_CLIENT_ID
spring.security.oauth2.client.registration.google.client-secret=YOUR_GOOGLE_CLIENT_SECRET
spring.security.oauth2.client.registration.google.scope=profile,email

你需要替换 YOUR_GOOGLE_CLIENT_IDYOUR_GOOGLE_CLIENT_SECRET 为你从 Google Cloud Console 获得的实际值。

步骤 3:安全配置

更新你的 SecurityConfig 类,以支持 OAuth2 登录:

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .oauth2Login();
    }
}

这里我们配置了所有请求都需要认证,并且启用了 OAuth2 登录。

步骤 4:用户信息获取和处理

当用户通过 Google 登录后,你可能需要获取并处理用户信息。你可以通过实现 OAuth2UserService 来完成这一步:

import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User user = super.loadUser(userRequest);
        // 处理用户信息逻辑
        return user;
    }
}

步骤 5:运行和测试

启动应用程序并访问 http://localhost:8080/。现在,你应该能看到一个通过 Google 登录的选项。使用你的 Google 账户登录,并验证登录流程是否正常工作。

通过这个案例,你可以看到如何在 Spring Boot 应用中轻松集成 OAuth2 社交登录。这个功能不仅提高了用户体验,还增强了应用的安全性。

1.1.4 拓展案例 2:JWT 认证

在这个案例中,我们将演示如何在 Spring Boot 应用中实现基于 JSON Web Token (JWT) 的认证。JWT 是一种广泛使用的技术,用于在客户端和服务器之间安全地传输信息。

案例 Demo

假设我们正在开发一个 RESTful API,我们希望通过 JWT 来认证和授权用户。

步骤 1:添加 JWT 相关依赖

首先,在你的 pom.xml 文件中添加 JWT 的依赖。我们将使用 java-jwt 库:

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.3</version>
</dependency>

步骤 2:实现 JWT 工具类

创建一个 JWT 工具类来生成和解析 JWT。这个类将负责创建令牌、验证令牌以及解析令牌:

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;

import java.util.Date;

public class JwtUtil {
    private static final String SECRET_KEY = "your_secret_key";

    public static String createToken(String username) {
        return JWT.create()
                .withSubject(username)
                .withExpiresAt(new Date(System.currentTimeMillis() + 864000000)) // 设置过期时间
                .sign(Algorithm.HMAC256(SECRET_KEY));
    }

    public static String validateTokenAndRetrieveSubject(String token) {
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET_KEY)).build();
            DecodedJWT jwt = verifier.verify(token);
            return jwt.getSubject();
        } catch (JWTVerificationException exception) {
            //Invalid signature/claims
            return null;
        }
    }
}

步骤 3:配置 Spring Security

在 Spring Security 配置中,我们需要添加一个过滤器来检查传入的请求中的 JWT。

创建一个 JWT 过滤器类:

import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.FilterChain;
import java.io.IOException;
import java.util.Collections;

public class JwtFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            String username = JwtUtil.validateTokenAndRetrieveSubject(token);

            if (username != null) {
                UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
                        username, null, Collections.singletonList(new SimpleGrantedAuthority("USER")));
                SecurityContextHolder.getContext().setAuthentication(auth);
            }
        }
        chain.doFilter(request, response);
    }
}

然后,在 SecurityConfig 类中注册这个过滤器:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class);
    // 其他配置...
}

步骤 4:创建认证端点

在你的控制器中,创建一个端点用于生成 JWT:

@PostMapping("/authenticate")
public ResponseEntity<?> createAuthToken(@RequestParam String username) {
    String token = JwtUtil.createToken(username);
    return ResponseEntity.ok(token);
}

步骤 5:运行和测试

启动你的应用程序,然后向 /authenticate 端点发送一个请求,携带用户名。你应该会收到一个 JWT。然后,你可以使用这个 JWT 来访问受保护的资源。

通过这个案例,你可以看到如何在 Spring Boot 应用中使用 JWT 进行认证。JWT 认证在开发现代 Web 应用和微服务架构时非常有用,尤其是在处理跨域请求和轻量级认证时。

1.2 Spring Security 的核心特性

1.2.1 基础知识详解

Spring Security 的核心特性

  1. 认证和授权

    • 认证 是验证用户身份的过程。Spring Security 支持多种认证方式,包括但不限于用户名和密码验证、LDAP 认证、OAuth2、JWT 等。
    • 授权 则是决定已认证用户可以访问哪些资源的过程。Spring Security 允许你基于角色或更细粒度的权限来控制访问。
  2. CSRF 防护

    • CSRF 攻击是一种常见的网络攻击方式,它试图利用用户的登录状态执行未经授权的操作。Spring Security 提供了 CSRF 防护机制,默认情况下在所有的 POST 请求上启用。
  3. 会话管理

    • 会话管理涉及用户的登录会话和会话过期。Spring Security 提供了丰富的会话管理功能,包括会话固定保护和并发会话控制。
  4. 密码存储

    • Spring Security 支持多种密码存储格式,包括明文、哈希、PBKDF2、SCrypt 等,并且鼓励开发者使用强密码编码方式。
  5. 方法级安全

    • 除了 URL 级别的安全控制外,Spring Security 还支持方法级别的安全控制。这允许开发者直接在 Java 方法上应用安全注解,实现更细粒度的控制。
  6. LDAP 集成

    • 对于需要与 LDAP 目录服务集成的应用程序,Spring Security 提供了简便的集成方式。这使得在企业环境中实现认证和授权变得容易。
  7. OAuth2 和 OpenID Connect

    • Spring Security 支持现代认证和授权协议,如 OAuth2 和 OpenID Connect,使得它可以与第三方认证提供者(如 Google、Facebook 等)轻松集成。
  8. 跨域资源共享(CORS)支持

    • 在开发 SPA(单页面应用程序)或调用跨域 API 时,CORS 是一个常见的问题。Spring Security 提供了 CORS 支持,允许开发者配置跨域请求的处理。

通过掌握这些基础知识,开发者可以利用 Spring Security 为他们的应用程序构建一个强大且灵活的安全系统。接下来的案例将更具体地展示如何将这些特性应用于实际开发中。

1.2.2 主要案例:基于角色的访问控制

在这个案例中,我们将演示如何在 Spring Boot 应用中实现基于角色的访问控制(RBAC)。我们假设有两种角色:“USER” 和 “ADMIN”,每种角色都有不同的访问权限。

案例 Demo

我们将创建一个简单的 Spring Boot 应用程序,其中包含两个受保护的页面:一个仅对普通用户开放,另一个仅对管理员开放。

实现步骤:

  1. 创建 Spring Boot 应用程序:
    使用 Spring Initializr 创建一个新的 Spring Boot 项目,并添加 spring-boot-starter-webspring-boot-starter-security 依赖。

  2. 配置安全性:
    创建一个继承自 WebSecurityConfigurerAdapter 的配置类来定义安全规则。

    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                .withUser("user").password("{noop}password").roles("USER")
                .and()
                .withUser("admin").password("{noop}adminpass").roles("ADMIN");
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                .antMatchers("/user").hasRole("USER")
                .antMatchers("/admin").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .logout();
        }
    }
    

    在这个配置中,我们定义了两个用户和他们的角色。同时,我们设置了 /user 只能被 USER 角色访问,/admin 只能被 ADMIN 角色访问。

  3. 创建控制器:
    创建一个控制器来管理不同的页面。

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @Controller
    public class MainController {
    
        @GetMapping("/user")
        public String user() {
            return "user";
        }
    
        @GetMapping("/admin")
        public String admin() {
            return "admin";
        }
    }
    
  4. 创建视图:
    useradmin 路径分别创建视图文件,例如 user.htmladmin.html

  5. 运行和测试:
    运行应用程序并访问 http://localhost:8080/userhttp://localhost:8080/admin。尝试使用不同的用户登录并验证它们是否能访问正确的页面。

通过这个案例,您将看到 Spring Security 如何实现基于角色的访问控制,这是构建安全 Web 应用程序的基础。这种方法可以确保用户只能访问他们被授权的资源。

1.2.3 拓展案例 1:表单登录与数据库用户存储

在这个案例中,我们将演示如何结合表单登录和数据库用户存储在 Spring Boot 应用中实现用户认证。这将涉及从数据库中加载用户信息,并根据这些信息进行认证。

案例 Demo

假设我们有一个应用程序,其中用户信息存储在数据库中。我们需要实现一个表单登录页面,用户可以使用其数据库中的凭据进行登录。

实现步骤:

  1. 添加依赖:
    pom.xml 中添加 spring-boot-starter-data-jpa 和数据库相关的依赖,例如 spring-boot-starter-data-jpah2(作为示例数据库)。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    
  2. 配置数据源:
    application.properties 中配置数据库连接信息。对于 H2 数据库,可以使用内存模式。

    spring.datasource.url=jdbc:h2:mem:testdb
    spring.datasource.driverClassName=org.h2.Driver
    spring.datasource.username=sa
    spring.datasource.password=password
    spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
    
  3. 创建用户模型和仓库:
    定义一个用户实体类和一个继承 JpaRepository 的接口。

    import javax.persistence.Entity;
    import javax.persistence.Id;
    
    @Entity
    public class User {
        @Id
        private String username;
        private String password;
        // 省略 getter 和 setter
    }
    
    import org.springframework.data.jpa.repository.JpaRepository;
    
    public interface UserRepository extends JpaRepository<User, String> {
    }
    
  4. 实现 UserDetailsService:
    实现 UserDetailsService 接口,从数据库中加载用户信息。

    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.beans.factory.annotation.Autowired;
    
    public class CustomUserDetailsService implements UserDetailsService {
    
        @Autowired
        private UserRepository userRepository;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            User user = userRepository.findById(username)
                .orElseThrow(() -> new UsernameNotFoundException("User not found"));
            return new User(user.getUsername(), user.getPassword(), new ArrayList<>());
        }
    }
    
  5. 配置 Spring Security:
    配置 WebSecurityConfigurerAdapter,使用自定义的 UserDetailsService 和合适的密码编码器。

    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    
    @Autowired
    private CustomUserDetailsService userDetailsService;
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(new BCryptPasswordEncoder());
    }
    
  6. 创建登录表单:
    创建一个简单的 HTML 登录表单。

  7. 运行和测试:
    运行应用程序,并通过访问 http://localhost:8080/login 来测试登录功能。

通过这个案例,您可以了解如何结合表单登录和数据库用户存储来实现认证功能。这在实际开发中非常常见,为应用程序提供了更大的灵活性和安全性。

1.2.4 拓展案例 2:整合 OAuth2

在这个案例中,我们将演示如何在 Spring Boot 应用中整合 OAuth2,实现第三方登录。我们将以 Google 作为 OAuth2 提供商的例子来实现这一功能。

案例 Demo

假设我们有一个 Spring Boot 应用,需要让用户可以通过他们的 Google 账户登录。

实现步骤:

  1. 添加 OAuth2 客户端依赖:
    pom.xml 中添加 spring-boot-starter-oauth2-client 依赖。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    
  2. 配置 OAuth2 客户端:
    application.propertiesapplication.yml 中配置 Google 的 OAuth2 客户端信息。你需要替换 client-idclient-secret 为你在 Google API Console 中获取的实际值。

    spring.security.oauth2.client.registration.google.client-id=your-google-client-id
    spring.security.oauth2.client.registration.google.client-secret=your-google-client-secret
    spring.security.oauth2.client.registration.google.scope=profile,email
    
  3. 安全配置:
    修改你的 SecurityConfig 类,以支持 OAuth2 登录。

    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .oauth2Login();
    }
    

    这里我们配置了所有请求都需要认证,并且启用了 OAuth2 登录。

  4. 获取用户信息:
    创建一个控制器来处理登录后的用户信息。

    import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @Controller
    public class UserController {
    
        @GetMapping("/user")
        public String user(OAuth2AuthenticationToken token) {
            // 这里可以获取到用户信息
            // token.getPrincipal().getAttributes();
            return "user";
        }
    }
    
  5. 运行和测试:
    启动应用程序,并尝试通过访问 http://localhost:8080/user 使用 Google 账户登录。检查用户信息是否正确获取。

通过这个案例,您可以看到在 Spring Boot 应用中整合 OAuth2 并不复杂。这使得应用可以利用第三方服务提供商的强大认证机制,同时提高了用户体验。

1.3 Spring Security 的发展历程

1.3.1 基础知识详解

Spring Security 的演变

  1. 从 Acegi 到 Spring Security:

    • Acegi Security: 最初作为一个独立的安全框架,Acegi Security 为 Spring 应用提供了强大的安全性支持。
    • Spring Security 2.0: Acegi Security 被正式纳入 Spring 框架,并更名为 Spring Security。这个版本主要专注于简化配置,并引入了新的命名空间和注解驱动的安全配置。
  2. 功能增强和改进:

    • Spring Security 3.0: 引入了多项新特性,包括对注解的支持,使得开发者可以更灵活地配置安全策略。
    • Spring Security 4.0: 进一步增强了对 Java 配置的支持,减少了对 XML 的依赖。同时,增强了对 REST API 的安全支持。
  3. 适应现代应用的需求:

    • Spring Security 5.0: 标志着对现代应用安全的重大更新,包括对 OAuth2 和 OpenID Connect 的支持,以及对 Reactive 应用的安全支持。

核心特性的演进

  • 认证和授权: 从基本的表单登录和 HTTP 基本认证到支持 LDAP、OAuth2、OpenID Connect 和 JWT 等多样化认证方式。
  • 安全性控制的细化: 引入方法级别的安全控制,允许在不同方法上应用不同的安全策略。
  • 对 RESTful API 的支持: 随着 RESTful API 在现代应用中的普及,Spring Security 加强了对无状态 REST API 的安全性支持,例如通过 JWT 实现无状态认证。
  • 易用性和灵活性: 通过提供更多的 Java 配置选项,减少了对 XML 的依赖,使得配置更加灵活和易于理解。
  • 响应式编程的支持: 为适应 Spring WebFlux 和响应式编程模型的兴起,Spring Security 5 引入了对响应式应用的支持。

通过理解 Spring Security 的发展历程和其核心特性的演进,开发者可以更好地把握其使用方式和最佳实践,从而为应用程序提供强大而灵活的安全解决方案。

1.3.2 主要案例:表达式驱动的安全性

在这个案例中,我们将展示如何在 Spring Boot 应用中使用 Spring Security 的表达式驱动安全性,以实现更细粒度的访问控制。

案例 Demo

假设我们正在开发一个网上书店应用,需要实现以下安全需求:只有管理员可以添加书籍,而注册用户可以浏览书籍。

实现步骤:

  1. 创建 Spring Boot 应用程序:
    使用 Spring Initializr 创建一个新的 Spring Boot 项目,并添加 spring-boot-starter-webspring-boot-starter-security 依赖。

  2. 配置安全性:
    创建一个继承自 WebSecurityConfigurerAdapter 的配置类并开启方法级安全。

    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        // 配置用户认证逻辑
    }
    
  3. 设置用户角色和权限:
    configure(AuthenticationManagerBuilder auth) 方法中设置用户角色和权限。

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("admin").password("{noop}admin123").roles("ADMIN")
            .and()
            .withUser("user").password("{noop}user123").roles("USER");
    }
    
  4. 使用安全表达式:
    在你的服务类中使用安全注解来限制方法访问。

    import org.springframework.security.access.prepost.PreAuthorize;
    
    @Service
    public class BookService {
    
        @PreAuthorize("hasRole('ADMIN')")
        public void addBook(Book book) {
            // 逻辑添加书籍
        }
    
        @PreAuthorize("hasAnyRole('USER', 'ADMIN')")
        public List<Book> listBooks() {
            // 返回书籍列表
        }
    }
    
  5. 创建控制器:
    实现一个控制器,调用 BookService 的方法。

    @RestController
    public class BookController {
    
        @Autowired
        private BookService bookService;
    
        @PostMapping("/books")
        public ResponseEntity<String> addBook(@RequestBody Book book) {
            bookService.addBook(book);
            return ResponseEntity.ok("Book added successfully");
        }
    
        @GetMapping("/books")
        public ResponseEntity<List<Book>> getBooks() {
            return ResponseEntity.ok(bookService.listBooks());
        }
    }
    
  6. 测试安全性:
    运行应用程序,并使用不同角色的用户尝试访问 /books 的 GET 和 POST 方法。

通过这个案例,您可以看到如何在实际项目中使用 Spring Security 的表达式驱动安全性来实现基于角色的细粒度访问控制。这种方法为应用程序提供了强大的安全性和灵活性。

1.3.3 拓展案例 1:OAuth2 集成

在这个案例中,我们将展示如何在 Spring Boot 应用中整合 OAuth2,以便用户可以使用外部服务提供商进行认证。我们以集成 GitHub 作为 OAuth2 提供商为例。

案例 Demo

假设我们有一个 Spring Boot 应用,我们希望用户能够使用他们的 GitHub 账户登录。

实现步骤:

  1. 添加 OAuth2 客户端依赖:
    pom.xml 中添加 spring-boot-starter-oauth2-client 依赖。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    
  2. 配置 OAuth2 客户端:
    application.propertiesapplication.yml 中配置 GitHub 的 OAuth2 客户端信息。你需要在 GitHub 创建 OAuth 应用以获取 client-idclient-secret

    spring.security.oauth2.client.registration.github.client-id=your-github-client-id
    spring.security.oauth2.client.registration.github.client-secret=your-github-client-secret
    spring.security.oauth2.client.registration.github.scope=user:email
    
  3. 安全配置:
    修改你的 SecurityConfig 类,以支持 OAuth2 登录。

    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .oauth2Login();
    }
    

    这里我们配置了所有请求都需要认证,并且启用了 OAuth2 登录。

  4. 创建用户信息端点:
    创建一个控制器来显示登录用户的信息。

    import org.springframework.security.core.annotation.AuthenticationPrincipal;
    import org.springframework.security.oauth2.core.user.OAuth2User;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class UserController {
    
        @GetMapping("/user")
        public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) {
            return Collections.singletonMap("name", principal.getAttribute("name"));
        }
    }
    
  5. 运行和测试:
    启动应用程序,并尝试访问 http://localhost:8080/user。你应该能够看到一个重定向到 GitHub 的登录页面。使用你的 GitHub 凭据登录后,应用将显示你的 GitHub 用户名。

通过这个案例,你可以了解到如何在 Spring Boot 应用中实现 OAuth2 集成,从而允许用户使用外部服务提供商的账户进行认证,这对于提升用户体验和应用安全性都非常有帮助。

1.3.4 拓展案例 2:JWT 认证

在这个案例中,我们将演示如何在 Spring Boot 应用中使用 JSON Web Tokens (JWT) 实现无状态认证。这对于保护 REST API 尤其重要。

案例 Demo

假设我们正在开发一个提供 REST API 的应用程序,我们希望通过 JWT 来认证和授权用户。

实现步骤:

  1. 添加 JWT 依赖:
    pom.xml 中添加处理 JWT 的依赖库,例如 java-jwt

    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.10.3</version>
    </dependency>
    
  2. 实现 JWT Token 服务:
    创建一个服务类来生成和验证 JWT。

    import com.auth0.jwt.JWT;
    import com.auth0.jwt.algorithms.Algorithm;
    import java.util.Date;
    
    public class JwtTokenService {
    
        private static final String SECRET = "YourSecretKey";
    
        public String generateToken(String username) {
            return JWT.create()
                    .withSubject(username)
                    .withExpiresAt(new Date(System.currentTimeMillis() + 86400000)) // 1 day
                    .sign(Algorithm.HMAC256(SECRET));
        }
    
        public String validateTokenAndGetUsername(String token) {
            return JWT.require(Algorithm.HMAC256(SECRET))
                    .build()
                    .verify(token)
                    .getSubject();
        }
    }
    
  3. 创建 JWT 过滤器:
    创建一个 JWT 过滤器来拦截请求并验证 JWT。

    import javax.servlet.FilterChain;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.web.filter.OncePerRequestFilter;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    
    public class JwtFilter extends OncePerRequestFilter {
    
        private JwtTokenService jwtTokenService = new JwtTokenService();
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
            String token = request.getHeader("Authorization");
            if (token != null && token.startsWith("Bearer ")) {
                token = token.substring(7);
                String username = jwtTokenService.validateTokenAndGetUsername(token);
    
                if (username != null) {
                    UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, null);
                    SecurityContextHolder.getContext().setAuthentication(auth);
                }
            }
            filterChain.doFilter(request, response);
        }
    }
    
  4. 配置 Spring Security:
    WebSecurityConfigurerAdapter 中配置 JWT 过滤器。

    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.http.SessionCreationPolicy;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .addFilter(new JwtFilter())
            .authorizeRequests()
            .antMatchers("/api/protected").authenticated()
            .antMatchers("/api/public").permitAll();
    }
    
  5. 创建测试端点:
    创建一些测试用的 RESTful 端点。

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class TestController {
    
        @GetMapping("/api/protected")
        public String protectedHello() {
            return "Hello from protected API";
        }
    
        @GetMapping("/api/public")
        public String publicHello() {
            return "Hello from public API";
        }
    }
    
  6. 运行和测试:
    启动应用程序,并使用生成的 JWT 尝试访问 /api/protected。没有有效 JWT 的请求应该被拒绝。

通过这个案例,您可以看到如何在 Spring Boot 应用中实现基于 JWT 的认证。JWT 认证提供了一种有效的方式来保护 REST API,确保只有拥有有效令牌的用户才能访问受保护的资源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/416106.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

11.网络游戏逆向分析与漏洞攻防-游戏网络架构逆向分析-接管游戏接收网络数据包的操作

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;接管游戏发送数据的操作 码云地址&#xff08;master 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/titan 码云版本号&#xff1a;8256eb53e8c16281bc1a29cb8d26d352bb5bbf4c 代…

Android Duplicate class 排除重复类

一、起因&#xff1a; 在迭代开发的时候&#xff0c;发现2个ijk很多类重复。但又2个库实现的功能是不一样&#xff0c;目前不能合并。但又想保留2个功能。需要排除其中一个库。 二、报错如何下图&#xff1a; 三、解决方法&#xff1a; 3.1 在terminal 也就是命令行处输入 …

js 面试 什么是WebSockets?HTTP和HTTPS有什么不同?web worker是什么?

概念&#xff1a; webSocket 是一种在客户端和服务端之间建立持久连接的协议&#xff0c;它提供全双工通信通道&#xff0c;是服务器可以主动向客户端推送数据&#xff0c;同时也可以接受客户端发送的数据。 1 webSocket与https区别&#xff1f; 在网络通信中&#xff0c;We…

【mysql版本修改】

1、使用telnet确认当前mysql版本号 telnet <MySQL服务器IP地址> <MySQL端口号> telnet 192.168.38.20 33062、使用strings查看/usr/sbin/mysqld中包含版本号的字符串 # 查看/usr/sbin/mysqld文件中是否包含对应的版本号 strings /usr/sbin/mysqld | grep 5.7.30 …

Unity | 动态读取C#程序集实现热更新

目录 一、动态语言 二、创建C#dll 1.VS中创建一个C#语言的库工程 2.添加UnityEngine.dll的依赖 3.编写代码&#xff0c;生成dll 三、Unity使用dll 一、动态语言 计算机编程语言可以根据它们如何将源代码转换为可以执行的代码来分类为静态语言和动态语言。 静态语言&…

Spark Bloom Filter Join

1 综述 1.1 目的 Bloom Filter Join&#xff0c;或者说Row-level Runtime Filtering&#xff08;还额外有一条Semi-Join分支&#xff09;&#xff0c;是Spark 3.3对运行时过滤的一个最新补充   之前运行时过滤主要有两个&#xff1a;动态分区裁剪DPP&#xff08;开源实现&am…

ISO_IEC_18598-2016自动化基础设施管理(AIM)系统国际标准解读(一)

██ ISO_IEC_18598-2016是什么标准&#xff1f; ISO/IEC 18598国际标准是由ISO&#xff08;国际标准化组织&#xff09;/IEC&#xff08;国际电工委员会&#xff09;联合技术委员会1-信息技术的第25分委员会-信息技术设备互连小组制定的关于信息基础设施自动化管理的国际标准&…

C++中atomic的使用

atomic使用 概述介绍使用场景头文件atomic的使用创建load()store()exchange()compare_exchange_weakcompare_exchange_strong&#xff08;&#xff09;fetch_add()fetch_sub()fetch_and()fetch_or()fetch_xor() 示例实现代码运行结果 概述 本文只要讲述C11中atomic的使用&…

一文读懂Prometheus和Grafana的区别(适合小白)

Prometheus和Grafana是两种开源软件&#xff0c;分别用于监控和可视化数据。它们的主要功能和特点如下&#xff1a; Prometheus 监控系统&#xff1a;Prometheus是一个专门用于收集和存储时间序列数据的监控系统。它可以从各种目标&#xff08;如服务器、数据库等&#xff09…

Spring中的事务和事务的传播机制

事务是一组操作的集合&#xff0c;不可以被分割。事务会把所有的操作作为一个整体&#xff0c;这组操作要么全部成功&#xff0c;要么全部失败。 事务有三种操作&#xff1a; 开启事务&#xff1b;提交事务&#xff1b;回滚事务。 如果代码的执行逻辑是这样&#xff1a; 开…

NutUI + taro +vue 开发遇到的问题 使用popup组件 内部元素滚动遇到的的问题

1 popup 弹出内容时 弹出的框内元素数据很长需要滚动时 本地可以正常滚动 打包成小程序后无法滚动 如这样的免责条款内容 代码如下 解决办法 1 把2处的单位换成百分比 弹框能滚动但是 是popup 里面所有的元素都一起滚动 导致标题都滚走了 2 scroll-y 改成&#xff1a; :scrol…

Excel数据表定制分组排序

实例需求&#xff1a;某学校体育活动统计表如下图左侧表格所示&#xff0c;数据按照班级排列&#xff0c;现在需要根据如下规格对表格进行排序 “幼儿”班级排列在表格最后按照“次数”降序排列“幼儿”班级同样按“次数”降序排列 排序结果如下图中右侧表格所示。 示例代码…

GDB之(8)GDB-Server远程调试

GDB之(8)GDB-Server远程调试 Author&#xff1a;Once Day Date&#xff1a;2024年2月27日 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章请查看专栏: Linux实践记录_Once-Day的博客-CSDN博客 参考文档: 用GDB调试程序 _CSDN博客 _陈皓GDB: The GNU Project Debugger…

UE4c++ ConvertActorsToStaticMesh ConvertProceduralMeshToStaticMesh

UE4c ConvertActorsToStaticMesh 创建Edior模块&#xff08;最好是放Editor模块毕竟是编辑器代码&#xff09;创建蓝图函数UBlueprintFunctionLibraryUTestFunctionLibrary.hUTestFunctionLibrary.cpp:.Build.cs 目标:为了大量生成模型&#xff0c;我们把虚幻带有的方法迁移成函…

【数据结构与算法】回溯法解题20240229

【数据结构与算法】回溯法解题20240229 一、46. 全排列1、以[1,2,3]为例&#xff0c;抽象成树形结构2、回溯三部曲 二、LCR 084. 全排列 II1、以[1,1,2]为例&#xff0c;抽象成树形结构 三、面试题 08.07. 无重复字符串的排列组合四、面试题 08.08. 有重复字符串的排列组合 一、…

基于视觉识别的自动采摘机器人设计与实现

一、前言 1.1 项目介绍 【1】项目功能介绍 随着科技的进步和农业现代化的发展&#xff0c;农业生产效率与质量的提升成为重要的研究对象。其中&#xff0c;果蔬采摘环节在很大程度上影响着整个产业链的效益。传统的手工采摘方式不仅劳动强度大、效率低下&#xff0c;而且在劳…

163邮箱SMTP端口号及服务器地址详细设置?

163邮箱SMTP端口号是什么&#xff1f;163邮件SMTP设置教程&#xff1f; 除了基本的邮箱账号和密码外&#xff0c;还需要了解SMTP服务器地址和端口号&#xff0c;以及相应的设置。这些设置对于确保邮件能够顺利发送至关重要。下面&#xff0c;蜂邮EDM将详细介绍163邮箱SMTP端口…

http和https的区别是什么?

–前言 传输信息安全性不同、连接方式不同、端口不同、证书申请方式不同 一、传输信息安全性不同 1、http协议&#xff1a;是超文本传输协议&#xff0c;信息是明文传输。如果攻击者截取了Web浏览器和网站服务器之间的传输报文&#xff0c;就可以直接读懂其中的信息。 2、h…

《Redis 设计与实现》读书概要

注&#xff1a; 《Redis 设计与实现》一书基于 Redis 2.9 版本编写&#xff0c;部分内容已过时&#xff0c;过时之处本文会有所说明。本文为读书笔记&#xff0c;部分简单和日常使用较少的知识点未记录。原书网页版地址 https://redisbook.com/ 一、底层数据结构 SDS(Simple Dy…

微信小程序固定头部-CSS实现

效果图 代码逻辑&#xff1a;设置头部的高度&#xff0c;浮动固定后&#xff0c;再加个这个高度的大小的外边距 .weui-navigation-bar {position: fixed;top: 0px;left: 0px;right: 0px;height:90px; } .weui-navigation-bar_bottom{height:90px; }