我目前正在开发一个Spring-MVC应用程序,该应用程序承载我的html网页以及REST API(一种)。 问题取决于访问应用程序的内容,应该以不同的方式处理身份验证失败:
但是实际上,应用程序始终返回302,由浏览器处理,而没有机会让我的Javascript正确处理它。
从我的阅读中,我发现我必须定义2个WebSecurityConfigurerAdapter,我做到了,一个用于/ api,另一个用于网页,但是在两种情况下,它始终发送重定向302。
我的API配置是:
@Configuration
@Slf4j
@Order(SecurityProperties.BASIC_AUTH_ORDER - 5)
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/api/**")
.authenticated();
}
}
和网络配置:
@Configuration
@Slf4j
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/action/**", "/login", "/css/**")
.permitAll()
.anyRequest().authenticated().and()
.formLogin()
.loginPage("/login")
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
...
}
有人可以帮助我了解问题所在吗?
我看到了一些解决方案,这些解决方案读取Ajax响应的内容并在内部包含html的情况下进行重定向,但是我认为应该在服务器端对其进行正确处理。
答案 0 :(得分:1)
您需要自定义的REST身份验证入口点:
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized" );
}
}
还将其注册到WebSecurityConfigurerAdapter实现中的httpsecurity中,例如:
@Autowired
RestAuthenticationSuccessHandler restAuthenticationSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception{
http.
...
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.formLogin().loginProcessingUrl("/doLogin")
}
因此您将处理前台应用程序中未经授权的401。
另外,由于您具有REST,因此不需要.loginPage("/login")
,否则将被重定向,并且通过上述配置,您将不会被重定向(302),而是将401发送到在您的浏览器中运行的应用。在您的前端应用程序中,您会将凭据发布到“ / doLogin”。
答案 1 :(得分:1)
您似乎很近。请记住,在定义WebSecurityConfigurerAdapter
时,您需要说出要使用哪种身份验证机制:
@Configuration
@Slf4j
@Order(99)
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic(); // <-- use HTTP basic
}
}
此外,请注意requestMatchers
和authorizeRequests
之间的细微差别。当您有不同的WebSecurityConfigurerAdapter
时,它们会使用requestMatchers
按路径进行细分。
以上代码段的意思是“对于与/ api / **匹配的请求,请使用HTTP基本身份验证任何请求。”
为了网络安全,我们要处理“其他所有内容”,因此我们不需要requestMatchers()
。因此,要为您的网络安全做同样的事情,您需要这样做:
@Configuration
@Slf4j
@Order(100)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/action/**", "/login", "/css/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.and()
// ...
;
}
}
以上代码段的意思是“使用表单登录身份验证任何请求。”
最后,Spring Security将以WebSecurityConfigurerAdapter
升序处理@Order
。因此,请注意第一个是“ 99”,第二个是“ 100”。这意味着RestSecurityConfig
将在WebSecurityConfig
之前被处理。您可以将其视为if语句:
if (request matches /api) {
check the `RestSecurityConfig` configuration
} else {
check the `WebSecurityConfig` configuration
}