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


猜你喜欢
- 本文实例讲述了Android编程实现下载时主界面与详细界面一致更新的方法。分享给大家供大家参考,具体如下:1、创建监听管理类public c
- 本文实例讲述了Java计算文本MD5加密值的方法。分享给大家供大家参考,具体如下:java计算文本MD5值,用于加密import java.
- Android游戏开发中主要的类除了控制类就是显示类,
- 首先我们设计了模块层次图,当然图中只是给出一种实现方式,不局限于此。具体见下图。主要功能介绍如下:1)请求接口层。处理HTTP请求,及响应2
- 项目概况:Spring Cloud搭的微服务,使用了eureka,FeignClient,现在遇到FeignClient调用接口时不支持上传
- 我们使用Spring整合Quartz开发,本实例采用数据库模式的demo。xml文件配置如下:<?xml version="
- 前言列表是移动应用中用得最多的组件了,我们也会经常对列表元素进行增加或删除操作,最简单的方法是列表数据变动后,直接 setStat
- Elasticsearch简介Elasticsearch是什么?它能干什么?Elasticsearch(以下称之为ES)是一款基于Lucen
- 当你的应用需要显示一个进度条或需要用户对信息进行确认时,可以使用alertDialog来完成。下面来介绍常用的四种AlertDialog。1
- 一、前言在编码过程中,常常需要写打印日志语句,我们期望的是同一个业务的日志都在一块,在出问题的时候好根据日志来排查问题。而现实是在应用运行中
- mybatis的环境搭建:1、创建maven工程并且导入坐标:即我们需要在pop.xml文件中添加我们需要的依赖具体方法:搜索maven中央
- 一个是通过W、A、S、D来移动人物(示例一),另个是按屏幕上的按钮来移动人物(示例二)。很简单,只改了几行代码。下面是“Assets”文件夹
- 前言定时器线程池提供了定时执行任务的能力,即可以延迟执行,可以周期性执行。但定时器线程池也还是线程池,最底层实现还是ThreadPoolEx
- 目录首先必须要有一个个人微信公众号效果图后台路由代码完整代码首先必须要有一个个人微信公众号个人微信公众号相关的接口权限有限,不过用于个人学习
- 线程安全当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类
- Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动
- 前言Groovy 是一种基于 JVM 的动态语言,与 Java 语言紧密集成,可以很方便地在 Java 项目中使用。Groovy 有着简洁的
- 分转元private String fenToYuan(String amount){ NumberFormat format
- 本文实例为大家分享了Android检测手机多点触摸点数的具体代码,供大家参考,具体内容如下多点触摸点数效果图Circle.javapacka
- 一、前言在学习分治算法之前,问你一个问题,相信大家小时候都有存钱罐的经历,父母亲人如果给钱都会往自己的宝藏中存钱,我们每隔一段时间都会清点清