为什么这个 Spring Security 实现只检查密码,而不检查用户名?

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

Why this Spring Security implementation is checking only for the password and not for the username?

问题

以下是翻译好的内容:

我正在开发一个使用Spring Security的简单Spring Boot应用程序。我硬编码了一个用户名和密码,但问题是我可以使用任何用户名登录,只有密码会被Spring Security检查。

这是代码:

@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    public final MyUserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

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

MyUserDetailsService类:

@Service
public class MyUserDetailsService implements UserDetailsService {

    private static final String USERNAME = "john";
    private static final String PASSWORD = "$2a$10$5yPLXyd0J2TEHhsbD3Azjumpn6OePKsiV1XPpFaZfytT33mRAn3N6";

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return new org.springframework.security.core.userdetails
                .User(USERNAME, PASSWORD, new ArrayList<>());
    }
}

Rest Controller类:

@RestController
public class ApiController {

    @GetMapping("/hello")
    public String sendMoney() {
        return "Hello World!";
    }
}

我将用户名“john”和使用BCrypt加密的密码“test”硬编码在了代码中。但问题是,我可以使用任何用户名登录,只有密码应该是“test”。有人能解释一下为什么吗?为什么Spring Security只检查密码是否为“test”,而不检查用户名是否为“john”?任何反馈将不胜感激。谢谢!

英文:

I'm working on a simple Spring Boot app using Spring Security. And I hardcoded an username and password, but the problem is that I can login with any username, only the password is checked by Spring Security.

This is the code:

@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    public final MyUserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

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

MyUserDetailsService class:

@Service
public class MyUserDetailsService implements UserDetailsService {

    private static final String USERNAME = &quot;john&quot;;
    private static final String PASSWORD = &quot;$2a$10$5yPLXyd0J2TEHhsbD3Azjumpn6OePKsiV1XPpFaZfytT33mRAn3N6&quot;;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return new org.springframework.security.core.userdetails
                .User(USERNAME, PASSWORD, new ArrayList&lt;&gt;());
    }
}

Rest Controller class:

@RestController
public class ApiController {

    @GetMapping(&quot;/hello&quot;)
    public String sendMoney() {
        return &quot;Hello World!&quot;;
    }
}

I hardcoded the username "john" and password "test" encrypted with BCrypt. But the problem is that I can login with any username, only the password should be "test". Can somebody explain me why? Why Spring Security is checking only the password to be "test", but it doesn't check for the username to be "john"? Any feedback will be apreciated. Thank you!

答案1

得分: 2

这是按设计UserDetailsService.loadUserByUsername(String user) 旨在提供与user相对应的记录。可以使用硬编码的记录,但是那样的话,需要确保用户名是正确的。

但实际上,如果您希望 Spring Security 同时测试用户名和密码,则不应该实现自定义的 UserDetailService,而是直接使用提供了这些功能的 InMemoryUserDetailsManager

英文:

This is by design. UserDetailsService.loadUserByUsername(String user) is expected to provide the record corresponding to user. It is acceptable to use a hardcoded record, but then you are responsable to control that the user name is correct.

But in fact, if you want SpringSecurity to test both the user name and the password, you should not implement a custom UserDetailService, but directly use a InMemoryUserDetailsManager that provides it out of the box.

答案2

得分: 1

你似乎忽略了对参数 s 的使用:

    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

换句话说,无论代码被要求检索哪个用户详细信息,它都会检索预先编码的那些。用户 "notjohn"?当然,我们有。用户 "notexisting"?我们也有,等等。

我猜想你的意图是要检查 s 是否等于 "john",并且只有在请求的用户名是 "john" 时才返回预先编码的用户详细信息。

英文:

You seem to ignore the argument s to:

    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

so in other words - for whatever user details the code is asked to retrieve, it retrieves the hard-coded ones. User "notjohn"? Sure we have it. User "notexisting"? We also have it, etc.

I guess your intention is to have a check if s equals to &quot;john&quot; and only return the hard-coded user details if the requested username is &quot;john&quot;.

huangapple
  • 本文由 发表于 2020年10月23日 17:02:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/64497054.html
匿名

发表评论

匿名网友

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

确定