Spring Security AuthenticationManager 接口详解与实战

 更新时间:2025年10月22日 15:10:16   作者:小猿、  
Spring Security框架中的AuthenticationManager接口是认证体系的核心,负责验证用户身份,本文就来详细的介绍一下这一接口的工作原理、应用场景,感兴趣的可以了解一下

概述

在 Spring Security 框架中,AuthenticationManager 接口扮演着核心角色,负责处理认证请求并决定用户身份是否合法。本文将详细讲解这一接口的工作原理、应用场景,并结合 Spring Boot 3.4.3 版本提供实战示例。

AuthenticationManager 接口概述

AuthenticationManager 是 Spring Security 认证体系的核心接口,位于 org.springframework.security.authentication 包下,其定义非常简洁:

public interface AuthenticationManager {
    Authentication authenticate(Authentication authentication) 
        throws AuthenticationException;
}

该接口仅包含一个方法 authenticate(),用于处理认证请求,其工作流程如下:

  1. 接收一个 Authentication 对象作为参数,该对象包含用户提交的认证信息(如用户名 / 密码)
  2. 执行认证逻辑
  3. 认证成功时,返回一个包含完整用户信息和权限的 Authentication 对象
  4. 认证失败时,抛出 AuthenticationException 异常

核心实现类

在实际应用中,我们通常不会直接实现 AuthenticationManager 接口,而是使用其现成的实现类:

  1. ProviderManager

    • 最常用的实现类
    • 委托一个或多个 AuthenticationProvider 实例处理认证请求
    • 支持多种认证机制并存
  2. AuthenticationProvider

    • 不是 AuthenticationManager 的实现类,而是由 ProviderManager 调用
    • 每个 AuthenticationProvider 处理特定类型的认证请求
  3. DaoAuthenticationProvider

    • 常用的 AuthenticationProvider 实现
    • 通过 UserDetailsService 获取用户信息并验证密码

工作原理

AuthenticationManager 的认证流程可概括为:

  1. 客户端提交认证信息(如用户名 / 密码)
  2. 认证信息被封装成 Authentication 对象
  3. AuthenticationManager 接收该对象并调用 authenticate() 方法
  4. ProviderManager 会遍历其配置的 AuthenticationProvider 列表
  5. 找到支持当前 Authentication 类型的 AuthenticationProvider 并委托其进行认证
  6. 认证成功后,返回包含完整信息的 Authentication 对象
  7. 认证结果被 SecurityContext 存储,用于后续的授权判断

应用场景

AuthenticationManager 适用于各种需要身份认证的场景:

  1. 表单登录认证:处理用户名 / 密码登录
  2. API 认证:验证 API 密钥或令牌
  3. 多因素认证:结合多种认证方式
  4. 第三方登录:如 OAuth2、OpenID Connect 等
  5. 自定义认证:实现特定业务需求的认证逻辑

实战示例(Spring Boot 3.4.3)

下面我们将通过一个完整示例展示如何在 Spring Boot 3.4.3 中配置和使用 AuthenticationManager

1. 添加依赖

首先在 pom.xml 中添加必要依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 其他依赖 -->
</dependencies>

2. 配置 SecurityConfig

创建 Security 配置类,配置 AuthenticationManager 和安全规则:

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
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.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final UserDetailsService userDetailsService;

    public SecurityConfig(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    // 配置 AuthenticationProvider
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

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

    // 配置 AuthenticationManager
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }

    // 配置安全过滤链
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .defaultSuccessUrl("/api/home", true)
                .permitAll()
            )
            .logout(logout -> logout.permitAll());
            
        // 注册自定义的 AuthenticationProvider
        http.authenticationProvider(authenticationProvider());
        
        return http.build();
    }
}

3. 实现 UserDetailsService

创建自定义的 UserDetailsService 实现,用于加载用户信息:

package com.example.demo.service;

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.stereotype.Service;

import java.util.ArrayList;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 在实际应用中,这里应该从数据库或其他数据源加载用户信息
        if ("user".equals(username)) {
            return User.withUsername("user")
                    .password("$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW") // 密码是 "password"
                    .roles("USER")
                    .build();
        } else if ("admin".equals(username)) {
            return User.withUsername("admin")
                    .password("$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW") // 密码是 "password"
                    .roles("ADMIN", "USER")
                    .build();
        } else {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
    }
}

4. 创建认证控制器

创建一个控制器来演示如何在代码中使用 AuthenticationManager

package com.example.demo.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    private final AuthenticationManager authenticationManager;

    public AuthController(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @PostMapping("/login")
    public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {
        // 创建 Authentication 对象
        Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(
                loginRequest.getUsername(),
                loginRequest.getPassword()
            )
        );

        // 将认证结果存入 SecurityContext
        SecurityContextHolder.getContext().setAuthentication(authentication);
        
        // 返回认证成功的响应
        return ResponseEntity.ok(new JwtResponse("dummy-token", 
            authentication.getName(), 
            authentication.getAuthorities().toString()));
    }
    
    // 内部类用于接收登录请求
    public static class LoginRequest {
        private String username;
        private String password;
        
        // getters 和 setters
        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; }
    }
    
    // 内部类用于返回认证响应
    public static class JwtResponse {
        private String token;
        private String username;
        private String roles;
        
        public JwtResponse(String token, String username, String roles) {
            this.token = token;
            this.username = username;
            this.roles = roles;
        }
        
        // getters
        public String getToken() { return token; }
        public String getUsername() { return username; }
        public String getRoles() { return roles; }
    }
}

5. 测试接口

创建一个简单的测试接口来验证认证效果:

package com.example.demo.controller;

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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

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

    @GetMapping("/api/home")
    public String home() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return "Hello, " + auth.getName() + "! You have roles: " + auth.getAuthorities();
    }

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

自定义 AuthenticationManager

在某些场景下,我们可能需要自定义 AuthenticationManager 来实现特定的认证逻辑。例如,实现一个多因素认证:

package com.example.demo.config;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class CustomAuthenticationManager implements AuthenticationManager {

    private final List<AuthenticationProvider> providers;

    public CustomAuthenticationManager(List<AuthenticationProvider> providers) {
        this.providers = providers;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        AuthenticationException lastException = null;
        
        for (AuthenticationProvider provider : providers) {
            if (provider.supports(authentication.getClass())) {
                try {
                    // 调用 AuthenticationProvider 进行认证
                    Authentication result = provider.authenticate(authentication);
                    if (result.isAuthenticated()) {
                        // 可以在这里添加额外的认证逻辑,如多因素认证
                        return result;
                    }
                } catch (AuthenticationException e) {
                    lastException = e;
                }
            }
        }
        
        if (lastException != null) {
            throw lastException;
        }
        
        throw new BadCredentialsException("Authentication failed");
    }
}

总结

AuthenticationManager 是 Spring Security 认证体系的核心组件,负责协调认证过程并委托具体的认证逻辑给 AuthenticationProvider 实现。通过本文的讲解和示例,我们了解了:

  1. AuthenticationManager 的基本概念和工作原理
  2. 核心实现类及其各自的职责
  3. 在 Spring Boot 3.4.3 中如何配置和使用 AuthenticationManager
  4. 如何通过自定义实现来满足特定的认证需求

掌握 AuthenticationManager 的使用,将有助于我们更好地理解和扩展 Spring Security 的认证功能,为应用程序提供更安全、更灵活的身份验证机制。

到此这篇关于Spring Security AuthenticationManager 接口详解与实战的文章就介绍到这了,更多相关springsecurity authenticationmanager接口内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Maven3.9.9环境安装配置的实现步骤

    Maven3.9.9环境安装配置的实现步骤

    Maven是一个强大的项目管理和构建自动化工具,本文主要介绍了Maven3.9.9环境安装配置的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-05-05
  • Springboot引入多个yml方法(多种方案)

    Springboot引入多个yml方法(多种方案)

    SpringBoot默认加载的是application.yml文件,所以想要引入其他配置的yml文件,就要在application.yml中激活该文件这篇文章主要介绍了Springboot引入多个yml方法,需要的朋友可以参考下
    2019-10-10
  • 使用自定义注解实现redisson分布式锁

    使用自定义注解实现redisson分布式锁

    这篇文章主要介绍了使用自定义注解实现redisson分布式锁,具有很好的参考价值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • Linux中Elasticsearch的安装详细步骤

    Linux中Elasticsearch的安装详细步骤

    这篇文章主要介绍了Linux中Elasticsearch的安装详细步骤,Elasticsearch(ES)是一种分布式、可扩展的搜索和分析引擎,基于Lucene构建,它支持实时数据处理、全文搜索、实时分析等多种功能,需要的朋友可以参考下
    2024-12-12
  • JAVA SFTP文件上传、下载及批量下载实例

    JAVA SFTP文件上传、下载及批量下载实例

    本篇文章主要介绍了JAVA SFTP文件上传、下载及批量下载实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-03-03
  • springboot项目启动,但是访问报404错误的问题

    springboot项目启动,但是访问报404错误的问题

    这篇文章主要介绍了springboot项目启动,但是访问报404错误的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Java中的runnable 和 callable 区别解析

    Java中的runnable 和 callable 区别解析

    Runnable接口用于定义不需要返回结果的任务,而Callable接口可以返回结果并抛出异常,通常与Future结合使用,Runnable适用于简单的后台任务和定时任务,而Callable适用于并行计算、异步操作和复杂任务,选择使用哪个接口取决于具体的应用场景,感兴趣的朋友一起看看吧
    2025-03-03
  • 详解Java String字符串获取每一个字符及常用方法

    详解Java String字符串获取每一个字符及常用方法

    这篇文章主要介绍了详解Java String字符串获取每一个字符及常用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • 深入理解Java遗传算法

    深入理解Java遗传算法

    这篇文章主要为大家详细介绍了Java遗传算法,本文对基因的编码采用二进制规则,分享了对Java遗传算法的理解,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • 图解Java排序算法之快速排序的三数取中法

    图解Java排序算法之快速排序的三数取中法

    这篇文章主要为大家详细介绍了Java排序算法之快速排序的三数取中法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11

最新评论