springSecurity之AuthenticationProvider用法解析
作者:chihaihai 发布时间:2022-09-07 20:55:01
AuthenticationProvider解析
首先进入到AuthenticationProvider源码中可以看到它只是个简单的接口里面也只有两个方法:
public interface AuthenticationProvider {
// 具体认证流程
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
// supports函数用来指明该Provider是否适用于该类型的认证,如果不合适,则寻找另一个Provider进行验证处理。
boolean supports(Class<?> authentication);
}
AuthenticationProvider是用户自定义身份认证,认证流程顶级接口。
唯一作用即使用来进行身份验证,同时springSecurity也为我们提供了很多方便的实现类。
当我们没有指定相关AuthenticationProvider 对象时springSecurity默认使用的就时上图中的DaoAuthenticationProvider进行验证。
也就是最常见的账户名密码的方式。但是实际开发中我们往往需要实现自定义认证流程比如最常见的短信验证码,第三方登录等等。
这个时候我们就可以通过实现自己的 AuthenticationProvider方式来进行自定义认证。
只需要在WebSecurityConfigurerAdapter适配器类的config方法中加入自己实现的AuthenticationProvider 即可。
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
}
说到AuthenticationProvider就离不开AuthenticationManager这个接口
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
同样的AuthenticationManager也是一个顶级接口,可以看到它其中也定义了一个跟AuthenticationProvider一摸一样的方法。
如果说Auth ntic ationProvider是对认证的具体实现,则AuthenticationManager则是对我们众多AuthenticationProvider的一个统一管理。
Authentication Ma nager的实现有很多,通常使用ProviderManager对认证请求链进行管理。
从源码中可以看到
ProviderManager提供了一个list对AuthenticationProvider进行统一管理,即一个认证处理器链来支持同一个应用中的多个不同身份认证机制,ProviderManager将会根据顺序来进行验证。
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();
for (AuthenticationProvider provider : getProviders()) {
// 如果支持认证实现类就继续处理
if (!provider.supports(toTest)) {
continue;
}
if (debug) {
logger.debug("Authentication attempt using "
+ provider.getClass().getName());
}
try {
// 调用实现类的authenticate方法进行真实业务逻辑认证处理
result = provider.authenticate(authentication);
if (result != null) {
copyDetails(authentication, result);
break;
}
}
catch (AccountStatusException e) {
prepareException(e, authentication);
// SEC-546: Avoid polling additional providers if auth failure is due to
// invalid account status
throw e;
}
catch (InternalAuthenticationServiceException e) {
prepareException(e, authentication);
throw e;
}
catch (AuthenticationException e) {
lastException = e;
}
}
if (result == null && parent != null) {
// Allow the parent to try.
try {
result = parentResult = parent.authenticate(authentication);
}
catch (ProviderNotFoundException e) {
// ignore as we will throw below if no other exception occurred prior to
// calling parent and the parent
// may throw ProviderNotFound even though a provider in the child already
// handled the request
}
catch (AuthenticationException e) {
lastException = parentException = e;
}
}
if (result != null) {
if (eraseCredentialsAfterAuthentication
&& (result instanceof CredentialsContainer)) {
// Authentication is complete. Remove credentials and other secret data
// from authentication
((CredentialsContainer) result).eraseCredentials();
}
// If the parent AuthenticationManager was attempted and successful than it will publish an AuthenticationSuccessEvent
// This check prevents a duplicate AuthenticationSuccessEvent if the parent AuthenticationManager already published it
if (parentResult == null) {
// //发送认证成功事件
eventPublisher.publishAuthenticationSuccess(result);
}
return result;
}
// Parent was null, or didn't authenticate (or throw an exception).
if (lastException == null) {
lastException = new ProviderNotFoundException(messages.getMessage(
"ProviderManager.providerNotFound",
new Object[] { toTest.getName() },
"No AuthenticationProvider found for {0}"));
}
// If the parent AuthenticationManager was attempted and failed than it will publish an AbstractAuthenticationFailureEvent
// This check prevents a duplicate AbstractAuthenticationFailureEvent if the parent AuthenticationManager already published it
if (parentException == null) {
prepareException(lastException, authentication);
}
throw lastException;
}
来源:https://blog.csdn.net/chihaihai/article/details/104840650
猜你喜欢
- 文章来源:csdn 作者:wangfengsdu经常听到回调函数(callback function)这个概念, 所谓回调函数,就是指这个函
- 计算两点之间的距离然后在控制台输出,这个题目还是挺简单的。下面我们来看看具体代码。package com.swift;import java
- 基本思想:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后
- 自动登录是我们在软件开发时一个非常常见的功能,例如我们登录 QQ 邮箱:很多网站我们在登录的时候都会看到类似的选项,毕竟总让用户输入用户名密
- Android内部没有控件来直接显示文档,跳转WPS或其他第三方文档App体验性不好,使用腾讯X5内核能很好的解决的这一问题。一、下载腾讯X
- 一、数组创建1.1 声明并赋值int[] a = {1,2,3};1.2 声明数组名开辟空间并且赋值int[] a;a = new int[
- 本文实例为大家分享了java客户端登陆服务器用户名验证的具体实现代码,供大家参考,具体内容如下客户端通过键盘录入用户名,服务端对用户名进行验
- mybatis-plus作为mybatis的增强工具,简化了开发中的数据库操作。一旦遇到left join或right join的左右连接,
- 引言♀ 小AD:明哥,昨天气死我了,明哥要帮我出气。♂ 明世隐:咋了,有谁惹到你了。♀ 小AD:昨天辅助喷我小鲁班菜,我反手就对喷,然后竟然
- 静态数组Java中最基本的数组大家肯定不会陌生:int[] array = new int[6];for (int i = 0; i <
- 本文实例讲述了Java访问WebService返回XML数据的方法。分享给大家供大家参考。具体如下:import java.io.IOExc
- kafka-console-consumer.sh解读kafka-console-consumer.sh 脚本是一个简易的消费者控制台。该
- 此解决方案是针对window的,因为日志默认保存路径在C盘,linux忽略。学习RocketMQ过程中,总是出现com.alibaba.ro
- 1. 父工程构建1.1 Maven项目搭建环境版本JDK1.8Maven3.6+Maven模板maven-archetype-size删除父
- 一、IDEA自带打包插件内容:此种方式可以自己选择制作胖包或者瘦包,但推荐此种方式制作瘦包。输出:输出目录在out目录下流程步骤:第一步:
- MultipartResolver和ServletFileUpload冲突如果同时使用了MultipartResolver 和Servlet
- 问题由来一个简单的需求,要求把和当前用户相关的数据置顶展示。这里,我用了一个简单的用户表来复现这个需求。很简单,查询语句后面加上:order
- 谈到 Java 的线程池最熟悉的莫过于 ExecutorService 接口了,jdk1.5 新增的 java.util.concurren
- 一、需求场景有时候我们需要在项目中使用一些静态资源文件,比如城市信息文件 countries.xml,在项目启动后读取其中的数据并初始化写进
- 本文实例为大家分享了java实现微信扫码支付的具体代码,供大家参考,具体内容如下1、maven项目的pom.xml中添加如下jar包:<