认证源码分析与自定义后端认证逻辑

简介: 本文分析Spring Security认证流程,核心为`UsernamePasswordAuthenticationFilter`过滤器,负责提取用户名密码并封装成`UsernamePasswordAuthenticationToken`,交由`AuthenticationManager`处理。后者通过`ProviderManager`遍历`AuthenticationProvider`链完成认证,支持多种认证方式扩展,是安全框架的核心机制。

1.认证流程分析

UsernamePasswordAuthenticationFilter

先看主要负责认证的过滤器UsernamePasswordAuthenticationFilter,有删减,注意注释。

public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter
{
    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
    private String usernameParameter = "username";
    private String passwordParameter = "password";
    private boolean postOnly = true;
    
    public UsernamePasswordAuthenticationFilter() {
        super(new AntPathRequestMatcher("/login", "POST"));
    }
    
    public Authentication attemptAuthentication(HttpServletRequest request, 
                                                HttpServletResponse response) throws AuthenticationException {
        //必须为POST请求
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " +
                                                     request.getMethod());
        } else {
            
            String username = this.obtainUsername(request);
            String password = this.obtainPassword(request);
            
            if (username == null) {
                username = "";
            }
            
            if (password == null) {
                password = "";
            }
            
            username = username.trim();
            
            //将填写的用户名和密码封装到了UsernamePasswordAuthenticationToken中
            UsernamePasswordAuthenticationToken authRequest = new
            UsernamePasswordAuthenticationToken(username, password);
            
            this.setDetails(request, authRequest);
            //调用AuthenticationManager对象实现认证
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }
}

AuthenticationManager

由上面源码得知,真正认证操作在AuthenticationManager里面!

public class ProviderManager implements AuthenticationManager, MessageSourceAware,
InitializingBean {
    
    private static final Log logger = LogFactory.getLog(ProviderManager.class);
    private AuthenticationEventPublisher eventPublisher;
    private List<AuthenticationProvider> providers;
    protected MessageSourceAccessor messages;
    private AuthenticationManager parent;
    private boolean eraseCredentialsAfterAuthentication;
    
    //注意AuthenticationProvider这个对象,SpringSecurity针对每一种认证,什么qq登录啊,
    //用户名密码登陆啊,微信登录啊都封装了一个AuthenticationProvider对象。
    public ProviderManager(List<AuthenticationProvider> providers) {
        this(providers, (AuthenticationManager)null);
    }
    
    public Authentication authenticate(Authentication authentication) throws
    AuthenticationException {
        
        Class<? extends Authentication> toTest = authentication.getClass();
        AuthenticationException lastException = null;
        AuthenticationException parentException = null;
        Authentication result = null;
        Authentication parentResult = null;
        boolean debug = logger.isDebugEnabled();
        Iterator var8 = this.getProviders().iterator();
        
        //循环所有AuthenticationProvider,匹配当前认证类型。
        while(var8.hasNext()) {
            AuthenticationProvider provider = (AuthenticationProvider)var8.next();
            if (provider.supports(toTest)) {
                if (debug) {
                    logger.debug("Authentication attempt using " +
                                 provider.getClass().getName());
                }
                try {
                    //找到了对应认证类型就继续调用AuthenticationProvider对象完成认证业务。
                    result = provider.authenticate(authentication);
                    if (result != null) {
                        this.copyDetails(authentication, result);
                        break;
                    }
                } catch (AccountStatusException var13) {
                    this.prepareException(var13, authentication);
                    throw var13;
                } catch (InternalAuthenticationServiceException var14) {
                    this.prepareException(var14, authentication);
                    throw var14;
                } catch (AuthenticationException var15) {
                    lastException = var15;
                }
            }
        }
        
        if (result == null && this.parent != null) {
            try {
                result = parentResult = this.parent.authenticate(authentication);
            } catch (ProviderNotFoundException var11) {
            } catch (AuthenticationException var12) {
                parentException = var12;
                lastException = var12;
            }
        }
        
        if (result != null) {
            if (this.eraseCredentialsAfterAuthentication && result instanceof
                CredentialsContainer) {
                ((CredentialsContainer)result).eraseCredentials();
            }
            if (parentResult == null) {
                this.eventPublisher.publishAuthenticationSuccess(result);
            }
            return result;
        } else {
            if (lastException == null) {
                lastException = new
                ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound", new
                                                                   Object[]{toTest.getName()}, "No AuthenticationProvider found for {0}"));
            }
            if (parentException == null) {
                this.prepareException((AuthenticationException)lastException, authentication);
            }
            throw lastException;
        }
    }
}
相关文章
|
3月前
|
XML Java 数据格式
Spring @Configuration 注解详解:用 Java 代码替代 XML 配置
`@Configuration` 是 Spring 实现 Java 配置的核心注解,替代传统 XML,通过 `@Bean` 注册 Bean,结合 `@Import`、`@ComponentScan` 等实现类型安全、可维护的配置方式,推动 Spring 应用现代化。
|
3月前
|
SQL Java 数据库连接
MyBatis 分页机制详解:从 RowBounds 到物理分页实践
MyBatis分页策略解析:逻辑分页(RowBounds)将全量数据加载至内存,仅适用于小数据量;物理分页通过SQL层面限制返回数据,性能更优。推荐使用PageHelper插件,自动适配数据库方言,一行代码实现高效分页,避免OOM风险,提升系统稳定性。
|
3月前
|
SQL Java 关系型数据库
MyBatis 动态 SQL 详解:灵活构建复杂查询条件
MyBatis提供强大的动态SQL机制,通过`&lt;if&gt;`、`&lt;where&gt;`、`&lt;foreach&gt;`等标签实现条件判断、循环拼接,避免手动字符串处理。支持智能WHERE、SET生成,兼容多数据库模糊查询,提升代码安全性与可维护性,适用于复杂查询、批量操作等场景。
|
3月前
|
SQL 监控 安全
常见网络攻击类型详解:从原理到防御
本文系统介绍8种常见网络攻击类型,包括恶意软件、网络钓鱼、中间人攻击、DDoS、SQL注入等,剖析其原理与防御策略,助力提升个人与企业网络安全防护能力。
|
3月前
|
JSON 前端开发 安全
用自定义注解 + 拦截器实现登录鉴权
通过自定义注解 `@Login` 结合 Spring 拦截器,实现声明式登录校验。无需重复编码,自动拦截未登录请求,提升代码可维护性与安全性,适用于前后端分离架构的权限控制实践。
|
3月前
|
NoSQL Shell Linux
Windows 系统下的 MongoDB 单机部署
本文详细介绍 MongoDB 在 Windows 和 Linux 系统中的单机部署方法,涵盖下载安装、目录配置、服务启停、Shell 与 Compass 连接等步骤,助你快速搭建开发与生产环境。
|
3月前
|
SQL 安全 Java
了解 SQL 注入:原理、危害与防御
SQL注入是Web安全头号威胁,攻击者通过恶意SQL代码窃取、篡改或删除数据。本文详解其原理、危害及防御方案,强调预编译、输入校验、最小权限等核心防护措施,助你筑牢数据库安全防线。
|
3月前
|
安全 固态存储 Java
通用权限管理模型详解:从 ACL 到 RBAC0/1/2/3
本文深入解析ACL与RBAC两种主流权限模型,重点剖析RBAC的四个层级(RBAC0-RBAC3),涵盖角色继承、职责分离等核心机制,并结合实际场景给出选型建议,助你构建安全、可维护的权限体系。
|
3月前
|
缓存 安全 数据挖掘
数据库设计三范式:从理论到实战
本文深入浅出讲解数据库三范式(1NF、2NF、3NF),通过真实案例解析各范式的核心要求与常见误区,强调“范式是工具而非教条”,帮助开发者在规范性与性能间找到平衡,构建合理、易维护的数据模型。
|
3月前
|
监控 前端开发 Java
Spring Boot 统一异常处理与全局响应增强
本文介绍如何在Spring Boot中实现全局异常处理,通过`@RestControllerAdvice`和自定义`BusinessException`统一拦截异常,结合`JsonResult`标准化响应格式,避免信息泄露,提升前后端协作效率与系统健壮性。

热门文章

最新文章