春季安全性:应用程序共享网页和REST API

时间:2020-04-10 14:42:32

标签: javascript spring-security

我目前正在开发一个Spring-MVC应用程序,该应用程序承载我的html网页以及REST API(一种)。 问题取决于访问应用程序的内容,应该以不同的方式处理身份验证失败:

  • 如果用户使用浏览器访问页面,则必须将其重定向到登录页面(由浏览器管理的登录页面)
  • 如果它是页面(本例中为jquery数据表)中的组件,试图通过Ajax加载结果的下一页,则我应该收到401状态,以允许我在JS中解释它并重定向到登录页面。

但是实际上,应用程序始终返回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的情况下进行重定向,但是我认为应该在服务器端对其进行正确处理。

2 个答案:

答案 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
    }
}

此外,请注意requestMatchersauthorizeRequests之间的细微差别。当您有不同的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
}
相关问题