如何使用WebSecurityConfigurerAdapter定义自定义UserDetailsS​​ervice?

如何解决如何使用WebSecurityConfigurerAdapter定义自定义UserDetailsS​​ervice?

对于如何正确扩展WebSecurityConfigurerAdapter以正确使用自定义UserDetailsService并将其公开为bean,我有些困惑。 我的意思是:

  • userDetailsService():Javadoc说:

    允许从以下位置修改和访问UserDetailsService userDetailsServiceBean(),而无需与 ApplicationContext。开发人员应在以下情况下重写此方法 更改userDetailsServiceBean()的实例。

  • userDetailsServiceBean():Javadoc说:

    重写此方法以显示从UserDetailsService创建的 configure(AuthenticationManagerBuilder)作为bean。 [...] 改变 实例返回后,开发人员应进行更改 改为userDetailsService()

  • configure(AuthenticationManagerBuilder):Javadoc说:

    [...] authenticationManagerBean()方法可用于公开 得到的AuthenticationManager作为Bean。的 userDetailsServiceBean()可用于显示最后填充的 UserDetailsService是使用 AuthenticationManagerBuilder作为Bean。 UserDetailsService 也会自动填充到 HttpSecurity#getSharedObject(Class)与其他人一起使用 SecurityContextConfigurer(即RememberMeConfigurer)”

如果我刚刚读过这篇文章,我就会明白:

  • configure(AuthenticationManagerBuilder)配置一个AuthenticationManager,可以通过覆盖authenticationManagerBean()并将其标记为@Bean来暴露它;建立AuthenticationManagerconfigure(AuthenticationManagerBuilder)建立并连线UserDetailsService
  • 覆盖userDetailsServiceBean()(以@Bean标记)可以暴露通过先前方法构建和连接的UserDetailsService
  • 如果我希望configure(AuthenticationManagerBuilder)使用自己的UserDetailsService实现,则必须重写userDetailsService()才能返回它;然后将通过覆盖userDetailsServiceBean()
  • 来公开它

所以我最终得到了这个

@Override
protected void configure(final AuthenticationManagerBuilder auth)
    throws Exception {
  final MyUserDetailsService userDetailsService = userDetailsService();
  auth.userDetailsService(userDetailsService);
  // all the other configuration has been omitted
}

@Override
protected MyUserDetailsService userDetailsService() {
  return new MyUserDetailsService();
}

@Bean
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
  return super.userDetailsServiceBean();
}

但是,这是令我困惑和看到的东西:

  • configure(final AuthenticationManagerBuilder auth)的默认实现基本上不执行任何操作(只需将disableLocalConfigureAuthenticationBldr设置为true),尤其是它不会调用userDetailsService();这是我的首要任务,所以是通过使用UserDetailsService注入自定义userDetailsService()实现的原因;换句话说,如果我不重写userDetailsService()并直接在UserDetailsService中创建自定义configure(final AuthenticationManagerBuilder auth)实例,我将得到相同的结果
  • 可能与上述情况有关:userDetailsService()的默认实现与userDetailsServiceBean()的默认实现完全相同...我希望后者迟早会委派给前者,但是如果以前的默认实现实际上是相同的...我真的迷路了,我想知道为什么提供了两种不同的方法
  • 我希望通过上述操作,我的自定义MyUserDetailsService实现会在应用程序上下文中公开,但是如果我尝试在其他位置注入MyUserDetailsService实例,Springs会抱怨说没有这样的实例在我的应用程序上下文中;实际上,userDetailsServiceBean()返回的bean总是某种委派的包装器。如果我注入一个通用的UserDetailsService实例并尝试使用它,则会得到一个IllegalStateException,说“ UserDetailsS​​ervice是必需的”(org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.UserDetailsServiceDelegator.loadUserByUsername(String)中的委托机制无法检索正确的默认{{ 1}} ...)
  • 通过调试,我看到两次调用UserDetailsService(因此创建了两个userDetailsService()的DISTINCT实例),一次是通过上述MyUserDetailsService的实现,一次是由configure(final AuthenticationManagerBuilder auth)的调用...

因此,以上内容显然是不正确的(身份验证有效,因为将正确的org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.createSharedObjects()注入到UserDetailsService中,但是无法在应用程序上下文中公开AuthenticationManager),我可能通过简单地用UserDetailsService标记一个MyUserDetailsService bean或在我的@Service扩展中编写另一个@Bean方法来返回我的自定义{{1 }},因此绕过WebSecurityConfigurerAdapterUserDetailsService ...但是我不确定这是否是实现所需结果的最佳方法(出于某种原因,应该把这两种方法放在那儿。 )

我真的认为userDetailsService()的处理方式过于复杂...

解决方法

配置自定义UserDetailsService的方式取决于UserDetailsService的数量和UserDetailsService的种类。

还记得在Spring中公开bean的方法有多种:使用工厂方法(@Configuration)的@Bean,使用@ComponentScan的{​​{1}},XML等。 >

一个全局@Component

如果您要使用一个全局自定义UserDetailsService,则只需公开它,请参见Spring Security Reference

10.10.7。 UserDetailsS​​ervice

UserDetailsServiceUserDetailsService用于检索用户名,密码和其他用于使用用户名和密码进行身份验证的属性。 Spring Security提供DaoAuthenticationProvider的内存和JDBC实现。

您可以通过将自定义UserDetailsService公开为bean来定义自定义身份验证。例如,以下示例将假设UserDetailsService实现CustomUserDetailsService来自定义身份验证:

仅在未填充UserDetailsService并且未定义AuthenticationManagerBuilder时使用。

示例66.自定义UserDetailsS​​ervice Bean

AuthenticationProviderBean

@Bean CustomUserDetailsService customUserDetailsService() { return new CustomUserDetailsService(); } userDetailsService()的默认实现返回全局userDetailsServiceBean()。无需覆盖这些方法。

不同的UserDetailsService

如果您想对不同的UserDetailsService使用不同的UserDetailsService,则可以覆盖WebSecurityConfigurerAdapter#configure

WebSecurityConfigurerAdapter的默认实现用于尝试获取authenticationManager()。如果被覆盖,则应使用AuthenticationManager来指定AuthenticationManagerBuilder

并用AuthenticationManagerBuilder#userDetailsService添加它:

根据传入的自定义AuthenticationManager添加身份验证。然后返回一个UserDetailsService以允许自定义身份验证。

DaoAuthenticationConfigureruserDetailsService()的默认实现返回userDetailsServiceBean()中的UserDetailsService

如果要将AuthenticationManagerBuilder注入另一个组件,则可以覆盖UserDetailsService。如果公开多个userDetailsServiceBean(),则必须使用不同的bean名称。

内置UserDetailsService

UserDetailsService创建的一些内置UserDetailsService不会公开。

如果在其他组件中需要这样的AuthenticationManagerBuilder,则必须覆盖 UserDetailsService,请参见WebSecurityConfigurerAdapter#configure

例如,以下配置可用于在内存身份验证中注册,以公开内存中的UserDetailsS​​ervice:

userDetailsServiceBean()

如果公开多个@Override protected void configure(AuthenticationManagerBuilder auth) { auth // enable in memory based authentication with a user named // "user" and "admin" .inMemoryAuthentication().withUser("user").password("password").roles("USER").and() .withUser("admin").password("password").roles("USER","ADMIN"); } // Expose the UserDetailsService as a Bean @Bean @Override public UserDetailsService userDetailsServiceBean() throws Exception { return super.userDetailsServiceBean(); } ,则必须使用不同的bean名称。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-