Spring 引导安全自定义登录页面到不同 url“/”不工作

Spring Boot security custom Login page to different url "/" not working

我刚刚看了很多关于自定义登录页面的示例,每个示例都使用相同的“/login”路径。 经过如此多的挫折,我终于让登录使用默认设置。

我希望登录表单呈现在“/”处而不是登录处。

一旦通过身份验证,我希望它进入“/home”。

我假设 POST 仍然使用默认的“/login”?

我在 POST 表单“/”(与 GET 表单的路径相同)和“/login”

上都试过了

现在,当我尝试登录时,它不断将我重定向回与表单相同的“/”。

这里又是基本的 API 逻辑: 默认登录页面应位于“/”, 表单发布到“/login”, 登录后成功Url是"/home", “/home”和“/mama”是受保护的路线。 注销后,它应该重定向到“/”

我无法通过该应用程序,并且不确定是否缺少任何内容,它一直显示相同的表单登录,就好像我没有通过,即使密码显然没问题

以下是 WebConfigurerAdapter 文件管理器中解释的路由:

@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.userDetailsService(userDetailsService);

        /*auth.inMemoryAuthentication()
                .withUser("appuser").password("1234").roles("HEAD")
                .and()
                .withUser("Mama").password("Mama").roles("MAMA");*/

    }

    @Override
    /*
    * Now we have learnt the basics of Spring Security & Authrization method is completed.
    * Lets fix Authentication first!
    * Got it to work with hasAuthority & hasAnyAuthority but not with roles, not sure why, but it works atm
    *
    * */
    protected void configure(HttpSecurity http) throws Exception {
        //Disabled for development
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/mama").hasAuthority("MAMA")
                .antMatchers("/home").hasAnyAuthority("HEAD", "MAMA")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                    .loginPage("/").permitAll()
                    .defaultSuccessUrl("/home")
                    .usernameParameter("username")
                    .passwordParameter("password")
                .and()
                .logout()
                    .logoutSuccessUrl("/");
    }

    @Bean
    /*
    * Returning no op password encoder for now, as we are not encoding passwords as no registration
    * implemented for Prototype. We would need to add the users from a separate service. W
    *
    * */
    public PasswordEncoder getPasswordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

}



//LoginApi:
@RestController
public class LoginApi {

    @RequestMapping("/")
    public String index(){
        return "<form method='POST' action='/login'>" +
                "<div>" +
                "<input type='text' name='username' placeholder='Username: ' />" +
                "</div>" +
                "<div>" +
                "<input type='password' name='password' placeholder='Password: ' />" +
                "</div>" +
                "<div>" +
                "<input type='submit' name='submit' value='Login' />" +
                "</div>" +
                "</form>";
    }

    @RequestMapping("/home")
    public String home(){
        return "Welcome to Home!";
    }

    /*
    * This method can be deleted in the end
    * */
    @RequestMapping("/mama")
    public String roleTest(){
        return "This end point is only for Mama!";
    }

}

对于此测试,我没有使用数据库,但我有一个 UserPrincipal 和 UserDetailsS​​ervice 的有效实现,它们在默认登录设置下完美运行。 如果需要,很高兴分享该代码。 但是在这一点上,我看不出哪里出了问题。

如果有人想查看 UserDetailsS​​ervice 和 UserDetails 代码,也包含在内:

@Service
public class EmployeeDetailsService implements UserDetailsService {


    @Override
    /*
    * First, we are testing the Employee details service, independent of the Database, just to make sure we have this part working,
    * For the purpose of these prototypes, we wont use password encoder because we are not registering,
    *
    * */
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        if (!username.equals("Mama")){
            throw new UsernameNotFoundException("You got the wrong Username, should be mama");
        }

        Employee employee = new Employee();
        Role role = new Role();
        role.setName("HEAD");
        employee
                .setUsername(username)
                .setPassword("1234")
                .setRole(role);

        return new EmployeePrincipal(employee);

    }
}

public class EmployeePrincipal implements UserDetails {

    private Employee employee;


    public EmployeePrincipal(Employee employee){
        this.employee = employee;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority(employee.getRole().getName()));
        return  authorities;
    }

    @Override
    public String getPassword() {
        return employee.getPassword();
    }

    @Override
    public String getUsername() {
        return employee.getUsername();
    }

    /*
    * Methods below are the rubbish methods, we keep as true for now
    *
    * */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

请参阅网络附件中的图片,我不明白发生了什么? POST 请求正在使用 200 状态代码将 302 重定向回“/”?

无论凭据是对还是错,这种情况都会发生

如有任何建议,我们将不胜感激

CSRF 需要使用自定义表单来实现,因此对于测试和开发,最好禁用 CSRF

protected void configure(HttpSecurity http) throws Exception {
        //Disabled for development
        http.authorizeRequests()
                .antMatchers("/mama").hasAuthority("MAMA")
                .antMatchers("/home").hasAnyAuthority("HEAD", "MAMA")
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .formLogin()
                    .loginPage("/").permitAll()
                    .loginProcessingUrl("/login")
                    .defaultSuccessUrl("/home")
                .and()
                .logout()
                    .logoutSuccessUrl("/");
    }