如何在登录后将用户重定向到主页,并且使用Spring Security返回200而不是302?

huangapple go评论57阅读模式
英文:

How can I redirect users after logging in to the home page and throw out a 200 instead of a 302 with Spring Security?

问题

我目前正在尝试使用Spring Boot,并尝试创建一个带有REST后端的简单Web应用程序。我正在使用以下配置对用户进行身份验证:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
    private final PasswordEncoder passwordEncoder;
    private final UserDetailsServiceImpl dbUserDetailService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // 生成CSRF令牌(由于某种原因,它不会自动生成)
            .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            .and()

            // 现在我们根据规则授权请求
            .authorizeRequests()
            // 任何人都可以授权访问"/"
            .antMatchers("/", "/registration").permitAll()
            // 仅管理员角色可以请求POST "/registration"
            .antMatchers("/success").hasRole("USER")
            .anyRequest()
            .authenticated()
            .and()
            .formLogin()
            .loginPage("/")
            .permitAll()
            .and().csrf().disable()
            .logout()
            .logoutUrl("/logout")
            .clearAuthentication(true)
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID");
    }

    @Bean
    public AuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setPasswordEncoder(passwordEncoder);
        provider.setUserDetailsService(this.dbUserDetailService);
        return provider;
    }
}

目前,当用户成功登录时,不会返回200的HTTP状态代码,而是会返回302。同样,当用户登录失败(凭据错误)时,不会返回401,而是会返回302。我认为这种行为对我来说是有道理的,所以我认为我对Web应用程序的方法是错误的。

我想要实现的是,成功的登录尝试会返回一个状态码200,并将用户重定向到主页。登录尝试失败会返回一个状态码401,并且页面相同,只是会有一个指示登录尝试失败的消息。我如何实现这一点?

英文:

I'm currently experimenting with Spring Boot and trying to create a simple web app with a REST backend. I'm authenticating users with Spring Security, using the following configurations:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter{
private final PasswordEncoder passwordEncoder;
private final UserDetailsServiceImpl dbUserDetailService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// Generate a CSRF token (for some reason it doesn't do it automatically)
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
// Now we authorize requests based on our rules
.authorizeRequests()
// Anyone is authorized for a request to "/"
.antMatchers("/", "/registration").permitAll()
// Only admin roles can request to POST "/registration"
.antMatchers("/success").hasRole("USER")
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/")
.permitAll()
.and().csrf().disable()
.logout()
.logoutUrl("/logout")
.clearAuthentication(true)
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID");
}
@Bean
public AuthenticationProvider daoAuthenticationProvider(){
DaoAuthenticationProvider provider =
new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder);
provider.setUserDetailsService(this.dbUserDetailService);
return provider;
}
}

Currently, when the user successfully logins, instead of a 200 HTTP status code, it will send a 302. Likewise, when the user unsuccessfully does so (bad credentials), instead of a 401, it will send a 302. This behavior makes sense to me, so I think my approach to my web app is wrong.

What I'm trying to accomplish is that a successful login attempt results in a 200 status code and redirects the user to the home page. A bad login attempt results in a 401 status code and the page is the same except it'll have a message indicating that the attempt failed. How can I accomplish this?

答案1

得分: 1

如果您想要进行重定向,那么应该发送 302 状态码,而不是 200。这将告诉浏览器重定向到新的 URL。

所以您只需要在配置方法中设置一个重定向的成功 URL,这在这种情况下将是 defaultSuccessUrl

配置方法:

http
  .authorizeRequests()
  .antMatchers("/login*")
  .permitAll()
  .anyRequest()
  .authenticated()
  .and()
  .formLogin().defaultSuccessUrl("/homepage.html", true);

对于认证失败,您可以像本站的示例那样使用一个失败处理程序,链接如下:
https://www.baeldung.com/spring-security-custom-authentication-failure-handler

这适用于普通的基于 Spring 的 Web 应用程序。

如果您正在使用像 Angular 这样的前端框架,那么您应该覆盖成功和失败处理程序,并将其添加到配置方法中:

public class AppAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    protected void handle(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
    }
}

@Bean
public AuthenticationSuccessHandler appAuthenticationSuccessHandler() {
    return new AppAuthenticationSuccessHandler();
}

http
  .authorizeRequests()
  .antMatchers("/login*")
  .permitAll()
  .anyRequest()
  .authenticated()
  .and()
  .formLogin()
  .successHandler(new AppAuthenticationSuccessHandler())
  .failureHandler(new AppAuthenticationFailureHandler());

根据从 Spring 返回的响应代码(可能是 200 或 401),您应该在基于前端框架中进行重定向到主页或显示错误消息。

英文:

If you want to redirect, then you should send 302 instead of 200. This will give the browser indication to redirect to the new url.

so you just need to set a redirectSuccessUrl which in this case would be
defaultSuccessUrl in the configure method.

Configure Method

http
.authorizeRequests()
.antMatchers("/login*")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin().defaultSuccessUrl("/homepage.html", true);

For Authentication Failure you can use a failure handler like in this site
https://www.baeldung.com/spring-security-custom-authentication-failure-handler

This is for normal spring based web applications.

if you are using some frontend framework like Angular, then you should override the Success and Failure handler and add it configure method

public class AppAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler{
protected void handle(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
}
}
@Bean
public AuthenticationSuccessHandler appAuthenticationSuccessHandler(){
return new AppAuthenticationSuccessHandler();
}
http
.authorizeRequests()
.antMatchers("/login*")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.successHandler(new appAuthenticationSuccessHandler())
.failureHandler(new AppAuthenticationFailureHandler());

In the frontend framework based on the response code you get from spring which is either 200 or 401, you should do the redirection to homepage or show an error message

huangapple
  • 本文由 发表于 2020年9月18日 10:30:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/63948511.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定