我已经编写了一个APP,该APP到目前为止已经实现了登录表单。
我使用Spring-Boot 2.x,Java 9和Security ofc。
我的测试表明,用户在登录表单中输入的用户名实际上并不重要,只要用户密码正确,每个用户名都会被接受。
这让我非常困惑。
我希望这里有人可以提供帮助。如果您还有其他建议可以改善我的代码,请告诉我。
安全配置
@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();
}
}
用户
@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;
}
}
控制器中的相关方法
@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:";
}
注册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>
登录html
答案 0 :(得分:1)
您的问题在这里:
@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();
}
}
根据用户名定位用户。在实际的实现中,搜索可能区分大小写,或者不区分大小写,具体取决于实现实例的配置方式。在这种情况下,返回的UserDetails对象的用户名可能与实际请求的用户名不同。
强调地雷
因此,您应该按用户名找到UserDetails
。您的代码将忽略userName
并执行以下操作:
userRepo.findAll().iterator().next();
即您只需抓住所有用户,然后选择第一个并返回。
您的代码应执行以下操作:
userRepo.findByUsername(userName);
您需要确定UserDetails
中是否有UserRepo
的{{1}}与表单上提交的用户名相匹配。
TL; DR:用户名将被忽略,因为您忽略了用户名。