嗨,所有春季专家!
我有一个问题,我试图解决一段时间,但我认为我已经走到了尽头。
基本上我需要的是配置我的Spring-Security(在Spring-Boot中)有两种身份验证机制(一种用于Legacy JSP页面,一种用于REST API)。所以我按照以下帖子: multiple authentication mechanisms in a single app using java config
一个LDAP身份验证提供程序运行良好。但后来我尝试扩展我的LDAP连接,以便从第三方服务获取票证(将用于将来与其他服务的连接),并且我遇到了问题。
所以我创建了一个新的身份验证令牌,过滤器和身份验证提供程序,但无论我做什么,都会首先触发默认的UsernamePasswordAuthenticationFilter
。
我尝试关注此帖How to configure a custom filter programatically in Spring Security?,发现问题可能在于我的过滤器正在扩展UsernamePasswordAuthenticationFilter
。所以我删除了这个并尝试了一个简单的AbstractAuthenticationProcessingFilter
,仍然 - 没有运气。
我认为问题出在我的WebSecurity配置中。目前,通过以下代码我将要分享,REST Api身份验证返回 405 - 方法不允许并且旧版登录陷入无限循环并崩溃,甚至在我点击“登录”之前。
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //Enables @PreAuthorize on methods
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private LDAPConfigurationBean ldapBean;
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//HERE GOES LDAP CONNECTION STUFF
// Add the custom LDAP + Token provider to the Authentication provider chain
auth.authenticationProvider(new TicketAndLDAPAuthenticationProvider(authenticator,authoritiesPopulator));
// Creating an LDAP provider using the authenticator and the populator.
auth.authenticationProvider(new LdapAuthenticationProvider(authenticator,authoritiesPopulator));
}
@Configuration
@Order(1)
public static class ConfigureFilters extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.addFilterBefore(new TicketAndLDAPAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);
}
}
//Management Endpoints Authorization
@Configuration
@Order(2)
public static class EndpointsWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/manage/health")
.authorizeRequests()
.anyRequest().permitAll();
}
}
//API Authentication+Authorization
@Configuration
@Order(3)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private RestAuthSuccessHandler authSuccessHandler;
@Autowired
private RestAuthFailureHandler authFailureHandler;
@Autowired
private RestLogoutSuccessHandler logoutSuccessHandler;
private String LOGIN_PATH = "/api/authenticate";
private String USERNAME = "username";
private String PASSWORD = "password";
protected void configure(HttpSecurity http) throws Exception {
/*CSRF configuration*/
http.csrf().disable();
http
.antMatcher(LOGIN_PATH)
.authorizeRequests()
.anyRequest().permitAll();
http
.antMatcher("/api/**")
//Stateless session creation - no session will be created or used by Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.formLogin().permitAll()
.loginProcessingUrl(LOGIN_PATH)
.usernameParameter(USERNAME)
.passwordParameter(PASSWORD)
.successHandler(authSuccessHandler)
.failureHandler(authFailureHandler)
.and()
.logout().permitAll()
.logoutSuccessHandler(logoutSuccessHandler);
http
.authorizeRequests().anyRequest().authenticated();
}
}
//JSP Authentication+Authorization
@Configuration
@Order(4)
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
/*CSRF configuration*/
http.csrf().disable();
/*Static content*/
http
.authorizeRequests()
.antMatchers("/css*//**").permitAll()
.antMatchers("/images*//**").permitAll()
.antMatchers("/scripts*//**").permitAll()
.antMatchers("/fonts*//**").permitAll()
.antMatchers("/login*").anonymous();
/*Login / Logout configuration*/
http
.formLogin()
.loginPage("/login.htm").permitAll()
.defaultSuccessUrl("/index.htm?name=******")
.failureUrl("/login.htm?error=true")
.and()
.logout().permitAll()
.logoutSuccessUrl("/login.htm")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID");
/*URL roles authorizations*/
http
.authorizeRequests().anyRequest().authenticated();
}
}
}
正如您所看到的,我正在尝试在“配置过滤器”方法中配置我的过滤器 - 但我也尝试在适配器内配置它,带/不带@Bean
注释 - 所有都没有运气
过滤器:
public class TicketAndLDAPAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public TicketAndLDAPAuthenticationFilter() {
super("/*");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//Save the password for later
String username = request.getParameter("username");
String password = request.getParameter("password");
TicketAndLDAPAuthenticationToken token = new TicketAndLDAPAuthenticationToken(username,password,null);
return token;
}
}
修改:忘记添加到过滤器:
if ( request.getParameter( "username" ) == null || request.getParameter( "password" ) == null ) == null ) {
return null;
}
现在我在两种登录机制中都获得了405.
令牌:
public class TicketAndLDAPAuthenticationToken extends UsernamePasswordAuthenticationToken {
private AuthTicket otp;
private String restoredPassword;
public TicketAndLDAPAuthenticationToken( String username, String password, RestAuthLoginTicket otp ) {
super( username, password );
this.otp = otp;
}
public AuthTicket getOTP() {
return otp;
}
public AuthTicket getOtp() {
return otp;
}
public void setOtp(AuthTicket otp) {
this.otp = otp;
}
}
提供者:
public class TicketAndLDAPAuthenticationProvider extends LdapAuthenticationProvider {
@Autowired
TokenUtils tokenUtils;
public TicketAndLDAPAuthenticationProvider(LdapAuthenticator authenticator, LdapAuthoritiesPopulator authoritiesPopulator) {
super(authenticator, authoritiesPopulator);
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
TicketAndLDAPAuthenticationToken token = (TicketAndLDAPAuthenticationToken) super.authenticate(authentication);
token.setOtp(tokenUtils.getTicket(token));
return token;
}
@Override
public boolean supports(Class<?> authentication) {
return TicketAndLDAPAuthenticationToken.class.isAssignableFrom(authentication);
}
}
提前致谢!!
答案 0 :(得分:0)
所以我找到了问题。
首先,配置身份验证管理器的正确方法不是我上面配置的方式,因为没有antMatcher
这导致我的资源和页面对所有人开放。
其次,导致无限重定向和错误405的问题是我没有定义我的过滤器来接受帖子。
修复之后,我的JSP登录表单和身份验证机制运行正常,但是&#34; / api&#34;被重定向到登录页面而不是资源。
是什么让我想到了最后一点 - http.formLogin()
正在创建一个UsernamePasswordAuthenticationFilter
。我有两个 - 每次登录一个。所以我必须为每个登录添加http.addFilterBefore()
,但使用不同的URL。
&#34; / api&#34; url再次使用Spring的默认重定向而不是我定义的重定向,所以我不得不重写它们。
这些是适用于我的配置和过滤器:
安全配置:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //Enables @PreAuthorize on methods
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private LDAPConfigurationBean ldapBean;
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//LDAP Stuff
TicketAndLDAPAuthenticationProvider ticketAndLDAPAuthenticationProvider = new TicketAndLDAPAuthenticationProvider(authenticator,authoritiesPopulator);
auth.authenticationProvider(ticketAndLDAPAuthenticationProvider);
LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(authenticator,authoritiesPopulator);
auth.authenticationProvider(ldapAuthenticationProvider);
}
//Management Endpoints Authorization
@Configuration
@Order(1)
public static class EndpointsWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/manage/health")
.authorizeRequests()
.anyRequest().permitAll();
}
}
//API Authentication+Authorization
@Configuration
@Order(2)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private RestAuthSuccessHandler authSuccessHandler;
@Autowired
private RestAuthFailureHandler authFailureHandler;
@Autowired
private RestLogoutSuccessHandler logoutSuccessHandler;
private String LOGIN_PATH = "/api/authenticate";
protected void configure(HttpSecurity http) throws Exception {
/*CSRF configuration*/
http.csrf().disable();
http.addFilterBefore(new TicketAndLDAPAuthenticationFilter(LOGIN_PATH,authSuccessHandler,authFailureHandler), UsernamePasswordAuthenticationFilter.class);
http
.antMatcher("/api/**")
// Stateless session creation - no session will be created or used by Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.logout().permitAll()
.logoutSuccessHandler(logoutSuccessHandler);
http
.authorizeRequests().anyRequest().authenticated();
}
}
//JSP Authentication+Authorization
@Configuration
@Order(3)
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
private String LOGIN_PATH = "/login.htm";
@Override
protected void configure(HttpSecurity http) throws Exception {
/*CSRF configuration*/
http.csrf().disable();
http.addFilterBefore(new TicketAndLDAPAuthenticationFilter(LOGIN_PATH), UsernamePasswordAuthenticationFilter.class);
/*Static content*/
http
.authorizeRequests()
.antMatchers("/css*//**").permitAll()
.antMatchers("/images*//**").permitAll()
.antMatchers("/scripts*//**").permitAll()
.antMatchers("/fonts*//**").permitAll()
.antMatchers("/login*").anonymous();
/*Login / Logout configuration*/
http
.formLogin()
.loginPage(LOGIN_PATH).permitAll()
.defaultSuccessUrl("/index.htm?name=******")
.failureUrl("/login.htm?error=true")
.and()
.logout().permitAll()
.logoutSuccessUrl("/login.htm")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID");
/*URL roles authorizations*/
http
.authorizeRequests().anyRequest().authenticated();
}
}
}
过滤器:
public class TicketAndLDAPAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public TicketAndLDAPAuthenticationFilter(String defaultProcessUrl) {
super(new AntPathRequestMatcher(defaultProcessUrl, "POST"));
}
public TicketAndLDAPAuthenticationFilter(String defaultProcessUrl, AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) {
super(new AntPathRequestMatcher(defaultProcessUrl, "POST"));
setAuthenticationFailureHandler(authenticationFailureHandler);
setAuthenticationSuccessHandler(authenticationSuccessHandler);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//Save the password for later
String username = request.getParameter("username");
String password = request.getParameter("password");
if ( username==null || password==null) {
return null;
}
TicketAndLDAPAuthenticationToken token = new TicketAndLDAPAuthenticationToken(username,password,null);
return token;
}
}