Java 未调用自定义身份验证提供程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22453550/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Custom Authentication Provider Not Being Called
提问by Lee Theobald
I'm trying to setup a customer AuthenticationProvider with Spring Security but not having much luck getting it working. I'm using Java configurationso I'm probably missing something simple but as most the learning material is XML config based, it's not jumping out at me.
我正在尝试使用 Spring Security 设置客户 AuthenticationProvider,但没有太多运气让它工作。我正在使用Java 配置,所以我可能遗漏了一些简单的东西,但由于大多数学习材料都是基于 XML 配置的,因此它并没有引起我的注意。
This is using Spring v4.0.1.RELEASE but with Spring Security v3.2.2.RELEASE. Version number clash perhaps?
这是使用 Spring v4.0.1.RELEASE 但使用 Spring Security v3.2.2.RELEASE。也许版本号冲突?
As far as I could tell, all I had to do was create my provider:
据我所知,我所要做的就是创建我的提供者:
public class KBServicesAuthProvider implements AuthenticationProvider {
@Autowired
private ApplicationConfig applicationConfig;
@Autowired
private SessionServiceClient sessionServiceClient;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String email = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
try {
KBSessionInfo sessionInfo = sessionServiceClient.login(applicationConfig.getKbServicesPresenceId(), email,
password);
List<GrantedAuthority> grantedRoles = new ArrayList<>();
for (KBRoleMembership role : sessionInfo.getAuthenticatedUser().getRoleMemberships()) {
grantedRoles.add(new SimpleGrantedAuthority(role.getRoleId()));
}
return new UsernamePasswordAuthenticationToken(email, password, grantedRoles);
} catch (InvalidSessionException e) {
throw new AuthenticationCredentialsNotFoundException("Username or password was not accepted", e);
}
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
And then setup a class to describe my security setup. This class links in my provider:
然后设置一个类来描述我的安全设置。这个类在我的提供者中链接:
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired(required = true)
SessionServiceClient sessionServiceClient;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll().anyRequest().authenticated();
http.formLogin().loginPage("/login").permitAll().and().logout().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(getKBServicesAuthenticationProvider());
}
@Bean
protected AuthenticationProvider getKBServicesAuthenticationProvider() {
return new KBServicesAuthProvider();
}
}
But I'm not seeing anything in the logs & none of my debug points are being hit. The app acts as it's unsecured (so I can reach various URLs etc. still).
但是我在日志中没有看到任何内容,而且我的调试点都没有受到影响。该应用程序的行为是不安全的(因此我仍然可以访问各种 URL 等)。
Any ideas on what I should be checking?
关于我应该检查什么的任何想法?
采纳答案by Bal
This might not be the complete answer, as I'm struggling with this a bit myself. I'm using a custom authentication provider and a custom user details service. I see the same behavior as you -- breakpoints get hit in my user details service, but not in my authentication provider. Here is what my entire config class looks like:
这可能不是完整的答案,因为我自己也在为此苦苦挣扎。我正在使用自定义身份验证提供程序和自定义用户详细信息服务。我看到了与您相同的行为——断点在我的用户详细信息服务中被击中,但在我的身份验证提供程序中没有。这是我的整个配置类的样子:
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
AuthenticationProvider rememberMeAuthenticationProvider = rememberMeAuthenticationProvider();
TokenBasedRememberMeServices tokenBasedRememberMeServices = tokenBasedRememberMeServices();
List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>(2);
authenticationProviders.add(rememberMeAuthenticationProvider);
authenticationProviders.add(customAuthenticationProvider);
AuthenticationManager authenticationManager = authenticationManager(authenticationProviders);
http
.csrf().disable()
.headers().disable()
.addFilter(new RememberMeAuthenticationFilter(authenticationManager, tokenBasedRememberMeServices))
.rememberMe().rememberMeServices(tokenBasedRememberMeServices)
.and()
.authorizeRequests()
.antMatchers("/js/**", "/css/**", "/img/**", "/login", "/processLogin").permitAll()
.antMatchers("/index.jsp", "/index.html", "/index").hasRole("USER")
.antMatchers("/admin", "/admin.html", "/admin.jsp", "/js/saic/jswe/admin/**").hasRole("ADMIN")
.and()
.formLogin().loginProcessingUrl("/processLogin").loginPage("/login").usernameParameter("username").passwordParameter("password").permitAll()
.and()
.exceptionHandling().accessDeniedPage("/login")
.and()
.logout().permitAll();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**", "/img/**");
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(List<AuthenticationProvider> authenticationProviders) {
return new ProviderManager(authenticationProviders);
}
@Bean
public TokenBasedRememberMeServices tokenBasedRememberMeServices() {
return new TokenBasedRememberMeServices("testKey", userDetailsService);
}
@Bean
public AuthenticationProvider rememberMeAuthenticationProvider() {
return new org.springframework.security.authentication.RememberMeAuthenticationProvider("testKey");
}
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
I've just discovered that if I specifically add my authentication provider to the HttpSecurity object, my breakpoints start getting hit:
我刚刚发现,如果我专门将我的身份验证提供程序添加到 HttpSecurity 对象,我的断点开始被命中:
http
.csrf().disable()
.headers().disable()
.authenticationProvider(customAuthenticationProvider)
My goal is to get a BCryptPasswordEncoder working, which does not with this config -- everything returns as bad credentials. Anyway, just thought I'd share.
我的目标是让 BCryptPasswordEncoder 正常工作,这与此配置无关——一切都作为错误的凭据返回。无论如何,只是想我会分享。
回答by Nitin Prabhu
<security:global-method-security pre-post-annotations="enabled"/>
回答by Nitin Prabhu
Something like should be present in java config
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class HelloMethodSecurityConfig {
}
回答by Christopher Z
You forgot the @Autowired
annotation.
你忘了@Autowired
注释。
@Autowired
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(getKBServicesAuthenticationProvider());
}
Also, you may want to remove the .antMatchers("/").permitAll()
.
此外,您可能想要删除.antMatchers("/").permitAll()
.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
http.formLogin().loginPage("/login").permitAll().and().logout().permitAll();
}
回答by Nitesh Virani
@EnableWebMvcSecurity
will be deprecated in 4.0 https://jira.spring.io/browse/SEC-2790
@EnableWebMvcSecurity
将在 4.0 中弃用https://jira.spring.io/browse/SEC-2790
You might want to re consider you configuration.
您可能需要重新考虑您的配置。
回答by Steve Park
I had same issue (my custom auth provider is not hit) and solved the issue by introducing springSecurityFilterChain, after reading Why is Spring Security working in Tomcat but not when deployed to Weblogic?So my problem was maybe tied specifically with WebServer, but I had the custom auth provider issue also on Tomcat and checked my configuration works now on Tomcat.
我遇到了同样的问题(我的自定义身份验证提供程序未命中)并通过引入springSecurityFilterChain解决了该问题,阅读了为什么 Spring Security 在 Tomcat 中工作,但在部署到 Weblogic 时却没有?所以我的问题可能与 WebServer 相关,但我在 Tomcat 上也遇到了自定义身份验证提供程序的问题,并检查了我的配置现在在 Tomcat 上是否有效。
I'm using spring boot 1.4.1 version which contains Spring 4.3.3 and Spring Security 4.1.3 and following Traditional deployment
我正在使用 spring boot 1.4.1 版本,其中包含 Spring 4.3.3 和 Spring Security 4.1.3 并遵循传统部署
I tested my configuration against Tomcat v9.0and also WebLogic 12c R2and checked it worked on both. hope this helpful at least to someone using Tomcat.
我针对Tomcat v9.0和WebLogic 12c R2测试了我的配置,并检查它在两者上都有效。希望这至少对使用 Tomcat 的人有所帮助。
Below is my configuration started from main class.
下面是我从主类开始的配置。
Application.java
应用程序.java
public class Application {
public static void main( String[] args ) {
SpringApplication.run(new Class[] {AppConfig.class, Initializer.class, SecurityInitializer.class}, args);
}
}
Initializer.java
初始化程序.java
public class Initializer extends SpringBootServletInitializer implements WebApplicationInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(AppConfig.class);
}
@Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(WebConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = container.addServlet("my-servlet", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*");
}
}
Here the AbstractSecurityWebApplicationInitializer is building the springSecurityFilterChainfrom onStartup method. I didn't implement any, since I'm trying to use default configuration.
在这里,AbstractSecurityWebApplicationInitializer正在建设的springSecurityFilterChain从onStartup方法。我没有实现任何,因为我试图使用默认配置。
SecurityInitializer.java
安全初始化器.java
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
AppConfig.java
应用程序配置文件
@Configuration
@EnableAutoConfiguration
@EnableScheduling
@EnableMBeanExport
@EnableAsync
@EnableAspectJAutoProxy
@ComponentScan("com.my.package")
public class AppConfig {
}
SecurityConfig.java
安全配置文件
@Configuration
@EnableWebSecurity
@ComponentScan("com.my.package")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestfulRemoteAuthenticationProvider restfulRemoteAuthenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(restfulRemoteAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
WebConfig.java
配置文件
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.my.controller.package")
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public InternalResourceViewResolver internalViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
viewResolver.setOrder(1);
return viewResolver;
}
}
This is my custom auth provider to get authentication info from other component via Restful request
这是我的自定义身份验证提供程序,用于通过 Restful 请求从其他组件获取身份验证信息
RestfulRemoteAuthenticationProvider.java
RestfulRemoteAuthenticationProvider.java
@Component
public class RestfulRemoteAuthenticationProvider implements AuthenticationProvider {
@Autowired
private ManagementClientAdapterFactory managementClientAdapterFactory;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
// my logic to get and configure authSource which is my environment specific thing, also same for RemoteAuthRequestResult
RemoteAuthRequestResult result = (RemoteAuthRequestResult)authSource.sendRequest();
if(result.isAuthenticated()) {
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
return new UsernamePasswordAuthenticationToken(username, password, grantedAuths);
}
throw new BadCredentialsException("User not found by given credential");
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
回答by Mohit Sharma
I was facing the same Problem, The problem is with your method which will always return false.
我遇到了同样的问题,问题在于你的方法总是返回 false。
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals
(UsernamePasswordAuthenticationToken.class);
}
Change the above method to the below one and the problem will be resolved.
把上面的方法改成下面的方法,问题就解决了。
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class
.isAssignableFrom(authentication));
}
回答by Антон Сидякин
I had a similar problem, and this was because I used @Autowire-ed AuthenticationManager
instance, that was built by spring boot and simply not contained my custom AuthenticationProvider
.
我有一个类似的问题,这是因为我使用了 @Autowire-edAuthenticationManager
实例,它是由 spring boot 构建的,根本不包含我的自定义AuthenticationProvider
.
After two days of debugging of spring guts I finally realize that this is not same instance, as manager from org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#authenticationManager()
which I configured in my custom WebSecurityConfigurerAdapter
through WebSecurityConfigurerAdapter#configure(AuthenticationManagerBuilder)
.
经过两天的 spring 胆量调试后,我终于意识到这不是同一个实例,作为org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#authenticationManager()
我在自定义中配置的管理器WebSecurityConfigurerAdapter
通过WebSecurityConfigurerAdapter#configure(AuthenticationManagerBuilder)
.
Now I simply get this instance from WebSecurityConfigurerAdapter#authenticationManager()
and pass it to my GenericFilterBean
, which is handle my auth logic. Works fine.
现在我只是从这里获取这个实例WebSecurityConfigurerAdapter#authenticationManager()
并将它传递给 my GenericFilterBean
,这是处理我的身份验证逻辑。工作正常。
回答by Ricardo Gellman
Also, make sure you are sending the user and password with correct headers.
另外,请确保您使用正确的标题发送用户和密码。
Test curl below, and check the class is been invoked
下面测试 curl,并检查该类是否被调用
curl -X GET \ http://localhost:8080\ -H 'Authorization: Basic cmdlbGxtYW5AYnIuaWJtLmNvbTphYmM=' \ -H 'X-Requested-With: XMLHttpRequest' \ -H 'cache-control: no-cache'
curl -X GET \ http://localhost:8080\ -H '授权:基本 cmdlbGxtYW5AYnIuaWJtLmNvbTphYmM=' \ -H 'X-Requested-With: XMLHttpRequest' \ -H 'cache-control: no-cache'