Spring Boot / Spring Security,登录表单,用户名无关紧要

时间:2021-05-01 19:21:37

I have written an APP which has the login form implemented so far.

我写了一个APP,到目前为止已经实现了登录表单。

I use Spring-Boot 2.x, Java 9 and Security ofc.

我使用Spring-Boot 2.x,Java 9和Security ofc。

My tests showed that it actually doesn't matter what username the user enters in the login form, every username will be accepted as long the password of the user is correct.

我的测试显示,用户在登录表单中输入的用户名实际上并不重要,只要用户的密码正确,就会接受每个用户名。

This confuses me really much.

这让我很困惑。

I hope someone here can help. If you have any other suggestions for improving my code your oppinion please let me know.

我希望这里有人可以提供帮助。如果您有任何其他改进我的代码的建议,请告诉我。

SecurityConfiguration

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        return bCryptPasswordEncoder;
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

        // Setting Service to find User in the database.
        // And Setting PassswordEncoder
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // disable Cross Site Request Forgery
        http.csrf().disable();

        // The pages does not require login
        http.authorizeRequests()
                .antMatchers("/", "/login", "/register")
                .permitAll();

        // userInfo page requires login as ROLE_USER or ROLE_ADMIN.
        // If no login, it will redirect to /login page.
        // TODO ask if I really have to add every route here manually
        http.authorizeRequests()
                .antMatchers("/selectGet", "/success")
                .access("hasAnyRole('ROLE_ADMIN')");

        // When the user is not admin
        // But access a page that requires admin role,
        // AccessDeniedException will be thrown.
        http.authorizeRequests()
                .and()
                .exceptionHandling()
                .accessDeniedPage("/403");

        // Config for Login Form
        http.authorizeRequests().and().formLogin()//
                // Submit URL of login page.
                .loginProcessingUrl("/j_spring_security_check") // Submit URL
                .loginPage("/login")//
                .defaultSuccessUrl("/success")//
                .failureUrl("/login?error=true")//
                .usernameParameter("username")//
                .passwordParameter("password")
                // Config for Logout Page
                .and().logout().logoutUrl("/logout").logoutSuccessUrl("/logoutSuccessful");
    }
}

UserDetailsServiceImpl

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    UserRepo userRepo;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        if (userRepo.count() < 1) {
            System.out.println("SpringUser not found! " + userName);
            throw new UsernameNotFoundException("SpringUser " + userName + " was not found in the database");
        }
        return userRepo.findAll().iterator().next();
    }
}

User

@Entity
@EqualsAndHashCode
public class SpringUser implements UserDetails {

    // TODO https://spring.io/guides/gs/validating-form-input/
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    /*  @NotNull
      @Size(min = 2, max = 30)*/
    private String username;

    /*    @NotNull
        @Size(min = 4, max = 30)*/
    private String password;

    public SpringUser() {
    }

    public SpringUser(final String username, final String password) {
        this.username = username;
        this.password = EncrytedPasswordUtils.encrytePassword(password);
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> grantList = new ArrayList<>();
        grantList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        return grantList;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

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

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

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

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

Relevant methods from the controller

控制器的相关方法

@PostMapping("/register")
public String registerPost(@RequestParam("username") String username,
                           @RequestParam("password") String password) {
    System.out.println("post Register");
    SpringUser springUser = new SpringUser(username, password);
    userRepo.save(springUser);
    return "redirect:";
}

Register html

  <form method="post" th:action="@{/register}" >
                <input type="text" id="login" class="fadeIn second" name="username" placeholder="username" maxlength="10">
                <input type="text" id="password" class="fadeIn third" name="password" placeholder="password">
                <input type="submit" class="fadeIn fourth" value="Register">
            </form>

Login html

1 个解决方案

#1


1  

Your issue is here:

你的问题在这里:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    UserRepo userRepo;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        if (userRepo.count() < 1) {
            System.out.println("SpringUser not found! " + userName);
            throw new UsernameNotFoundException("SpringUser " + userName + " was not found in the database");
        }
        return userRepo.findAll().iterator().next();
    }
}

From the JavaDoc

来自JavaDoc

Locates the user based on the username. In the actual implementation, the search may possibly be case sensitive, or case insensitive depending on how the implementation instance is configured. In this case, the UserDetails object that comes back may have a username that is of a different case than what was actually requested.

根据用户名找到用户。在实际实现中,搜索可能区分大小写,或者不区分大小写,具体取决于实现实例的配置方式。在这种情况下,返回的UserDetails对象可能具有与实际请求的用户名不同的用户名。

emphasis mine

So, you are supposed to be locating the UserDetails by userName. Your code ignores the userName and does:

因此,您应该按userName查找UserDetails。您的代码忽略userName并执行:

userRepo.findAll().iterator().next();

i.e. you just grab all the users, then you take the first one and return it.

即你只是抓住所有用户,然后你拿第一个并返回它。

Your code should do:

你的代码应该做:

userRepo.findByUsername(userName);

You need to determine whether there is a UserDetails in the UserRepo with a userName that matches the username submitted on the form.

您需要确定UserRepo中是否存在UserDetails,其userName与表单上提交的用户名相匹配。


TL;DR: The username is ignored because you ignore the username.

TL; DR:忽略用户名,忽略用户名。

#1


1  

Your issue is here:

你的问题在这里:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    UserRepo userRepo;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        if (userRepo.count() < 1) {
            System.out.println("SpringUser not found! " + userName);
            throw new UsernameNotFoundException("SpringUser " + userName + " was not found in the database");
        }
        return userRepo.findAll().iterator().next();
    }
}

From the JavaDoc

来自JavaDoc

Locates the user based on the username. In the actual implementation, the search may possibly be case sensitive, or case insensitive depending on how the implementation instance is configured. In this case, the UserDetails object that comes back may have a username that is of a different case than what was actually requested.

根据用户名找到用户。在实际实现中,搜索可能区分大小写,或者不区分大小写,具体取决于实现实例的配置方式。在这种情况下,返回的UserDetails对象可能具有与实际请求的用户名不同的用户名。

emphasis mine

So, you are supposed to be locating the UserDetails by userName. Your code ignores the userName and does:

因此,您应该按userName查找UserDetails。您的代码忽略userName并执行:

userRepo.findAll().iterator().next();

i.e. you just grab all the users, then you take the first one and return it.

即你只是抓住所有用户,然后你拿第一个并返回它。

Your code should do:

你的代码应该做:

userRepo.findByUsername(userName);

You need to determine whether there is a UserDetails in the UserRepo with a userName that matches the username submitted on the form.

您需要确定UserRepo中是否存在UserDetails,其userName与表单上提交的用户名相匹配。


TL;DR: The username is ignored because you ignore the username.

TL; DR:忽略用户名,忽略用户名。