开发需了解的知识:Spring Security实现用户认证和授权

526 阅读4分钟

Spring Security 核心功能

  1. 认证(Authentication)

    • 功能:验证用户的身份是否合法。

    • 实现

      • 使用 AuthenticationManager 进行身份验证。
      • 支持多种认证方式(用户名密码、OAuth2、JWT、LDAP 等)。
      • 通过 UserDetailsService 加载用户详细信息。
  2. 授权(Authorization)

    • 功能:确定用户是否有权限访问某资源。

    • 实现

      • 基于 URL、方法、表达式的权限控制(@PreAuthorize@Secured)。
      • 权限评估由 AccessDecisionManager 完成。
      • 配置 HttpSecurity 管理请求级别的权限。
  3. 会话管理

    • 功能:管理用户会话状态,支持单点登录(SSO)和并发会话控制。

    • 实现

      • 使用 SessionManagementConfigurer 进行会话配置。
      • 支持跨站请求防护(CSRF)、记住我功能(Remember-Me)。
  4. 防护机制

    • CSRF 防护:内置防御跨站请求伪造攻击机制。
    • 密码存储:提供多种加密算法(如 BCrypt)存储用户密码。
    • 安全头配置:如 X-Content-Type-Options、X-XSS-Protection、Strict-Transport-Security 等。
  5. 扩展性

    • 自定义认证与授权:实现自定义的 AuthenticationProviderAccessDecisionVoter
    • 支持第三方登录:通过 OAuth2.0 和 OpenID Connect 实现社交登录。
    • 细粒度控制:如针对特定角色、IP 的访问规则配置。

Spring Security 实现原理

  1. 过滤器链(Filter Chain)

    • 核心机制是基于 Servlet 过滤器的链式调用。

    • DelegatingFilterProxy 将所有请求代理到 SecurityFilterChain

    • 常见过滤器:

      • UsernamePasswordAuthenticationFilter:处理用户名密码登录。
      • BasicAuthenticationFilter:处理 HTTP Basic 认证。
      • CsrfFilter:检查 CSRF 令牌。
      • ExceptionTranslationFilter:处理认证/授权异常。
  2. 认证流程

    • 用户提交认证请求(如表单登录)。
    • AuthenticationFilter 拦截请求并构造 Authentication 对象。
    • Authentication 交给 AuthenticationManager
    • AuthenticationManager 调用多个 AuthenticationProvider 验证身份。
    • 如果认证成功,返回认证后的 Authentication 对象存入 SecurityContextHolder
  3. 授权流程

    • 请求经过过滤器链后,进入 AccessDecisionManager
    • AccessDecisionManager 调用 AccessDecisionVoter 判断是否有权限访问资源。
    • 如果无权限,抛出 AccessDeniedException
  4. 密码加密与校验

    • 默认使用 PasswordEncoder(如 BCrypt)对密码进行加密存储。
    • 校验时,使用加密后的密码进行匹配,确保安全性。
  5. 会话管理

    • 通过 SecurityContextPersistenceFilter 维护会话上下文。
    • 支持会话过期、并发会话限制。

案例:实现用户认证和授权

功能描述

实现一个简单的用户认证和授权系统:

  1. 用户通过用户名和密码登录。
  2. 系统校验用户名密码的合法性,认证通过后访问受保护的资源。
  3. 只有具备特定角色的用户才能访问某些特定的接口。

实现步骤

1. 引入依赖

添加 Spring Security 相关依赖(pom.xml):

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

2. 配置认证逻辑

自定义用户认证逻辑,加载用户数据。

代码:UserDetailsService 实现

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // 密码加密
    }

    @Bean
    public UserDetailsService userDetailsService() {
        // 在内存中创建用户
        UserDetails user1 = User.builder()
                .username("admin")
                .password(passwordEncoder().encode("password")) // 加密后的密码
                .roles("ADMIN") // 赋予角色
                .build();

        UserDetails user2 = User.builder()
                .username("user")
                .password(passwordEncoder().encode("password"))
                .roles("USER")
                .build();

        return new InMemoryUserDetailsManager(user1, user2);
    }
}

3. 配置授权规则

配置 URL 的权限控制逻辑。

代码:HTTP 请求的授权配置

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityFilterConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable() // 关闭 CSRF,仅供演示
            .authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN") // 仅 ADMIN 可访问
                .antMatchers("/user/**").hasAnyRole("USER", "ADMIN") // USER 和 ADMIN 可访问
                .antMatchers("/public/**").permitAll() // 所有人都可访问
                .anyRequest().authenticated() // 其他请求需要认证
            .and()
            .formLogin() // 表单登录
                .loginPage("/login") // 自定义登录页
                .permitAll()
            .and()
            .logout() // 支持注销
                .permitAll();
        return http.build();
    }
}

4. 构建 Controller

代码:Controller 示例

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @GetMapping("/public/hello")
    public String publicEndpoint() {
        return "Hello, Public!";
    }

    @GetMapping("/user/hello")
    public String userEndpoint() {
        return "Hello, User!";
    }

    @GetMapping("/admin/hello")
    public String adminEndpoint() {
        return "Hello, Admin!";
    }
}

案例分析:实现的认证和授权

  1. 认证流程

    • 用户登录

      • 用户通过表单提交用户名和密码。
      • UsernamePasswordAuthenticationFilter 捕获登录请求,将用户名和密码封装成 UsernamePasswordAuthenticationToken
      • 通过 AuthenticationManager 验证,调用 UserDetailsService 加载用户信息。
      • 验证成功后,将用户的认证信息存储在 SecurityContextHolder 中。
  2. 授权流程

    • 请求访问接口

      • 每个 HTTP 请求都会经过 SecurityFilterChain
      • 根据配置的权限规则(antMatchers),判断用户是否具备访问权限。
      • 如果用户权限不匹配,返回 403 Forbidden;否则允许访问。

运行结果

  1. 访问 /public/hello:任何用户都可以访问。

  2. 访问 /user/hello

    • 未登录时跳转到登录页面。
    • 登录 user/password 后,可以访问。
  3. 访问 /admin/hello

    • 未登录或登录普通用户 user 无权限。
    • 登录 admin/password 后可以访问。