[英]Spring Boot/ Spring Security, login form, password checking
我有一個問題可能很容易,但我不明白。
我對Spring Boot不是很熟悉,很多事情都是自動發生的。 我想檢查是否有人在表單中寫入用戶名和密碼[並且他的帳戶已激活]。 用戶數據存儲在application.properties中配置的MySQL數據庫中。 我想檢查“user”表中是否存在提供用戶名的人,並檢查提供的密碼是否等於數據庫中的用戶密碼。 目前我可以從數據庫中輸入任何用戶名,密碼可以是隨機的(這對我來說很明顯,因為我不在任何地方檢查它,而且很奇怪,因為我覺得周圍的一切都說它工作正常)。 這對我來說聽起來很簡單,但我在StackOverflow或教程上找不到任何合適的解決方案。
我的一般問題是 - 我應該在何處以及如何從登錄表單中檢查密碼? 它是自動完成的(但它不能以某種方式工作),或者我應該編寫我的自定義控制器 /服務/方法來做到這一點? 如果需要自定義控制器,那么解決問題的方向應該是什么?
目前我不知道該往哪里去。 我希望所有與我的問題相關的剩余代碼都粘貼在這里。 提前感謝您提供有關該提示的所有提示和評論。
ApplicationSecurityAdapter類:
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class ApplicationSecurityAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/user/register").permitAll()
.antMatchers("/user/activate").permitAll()
.antMatchers("/user/activation-send").permitAll()
.antMatchers("/user/reset-password").permitAll()
.antMatchers("/user/reset-password-change").permitAll()
.antMatchers("/user/autologin").access("hasRole('ROLE_ADMIN')")
.antMatchers("/user/delete").access("hasRole('ROLE_ADMIN')")
.antMatchers("/img/**").permitAll()
.antMatchers("/images/**").permitAll()
.antMatchers("/fonts/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login").permitAll() // added permitAll()
.and()
.rememberMe().key(applicationSecret)
.tokenValiditySeconds(31536000);
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
}
UserService類:
@Service
public class UserService implements UserDetailsService {
@Value("${app.user.verification}") // set to YES
private Boolean requireActivation;
@Value("${app.secret}") // some random stuff
private String applicationSecret;
@Autowired
private UserRepository repo;
@Autowired
private HttpSession httpSession;
public final String CURRENT_USER_KEY = "CURRENT_USER";
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = repo.findOneByUserName(username);
if(user == null) {
throw new UsernameNotFoundException(username);
}
if(requireActivation && !user.getToken().equals("1")) {
Application.log.error("User [" + username + "] tried to log in, but his account is not activated.");
throw new UsernameNotFoundException(username + " did not activate his account.");
}
httpSession.setAttribute(CURRENT_USER_KEY, user);
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRole());
return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), auth);
}
}
UserController的:
@Controller
// @RequestMapping("/user/*")
public class UserController {
private Logger log = LoggerFactory.getLogger(UserController.class);
@Value("${app.user.verification}") // YES
private Boolean requireActivation;
@Value("users/")
private String userRoot;
@Autowired
private UserRepository userRepository;
@Autowired
protected AuthenticationManager authenticationManager;
@Autowired
private UserService userService;
@RequestMapping("/login")
public String login(User user) {
return "user/login";
}
}
登錄表格:
<div layout:fragment="content">
<form class="form-signin" th:action="@{/login}" th:object="${user}" method="post">
<h2 class="form-signin-heading">LOGIN PANEL</h2>
<div class="alert alert-danger" th:if="${param.error}">
Incorrect credentials or account not activated.
</div>
<input type="text" id="inputUsername" name="username" class="form-control top" placeholder="username goes here..." required="required" autofocus="autofocus"/>
<input type="password" id="inputPassword" name="password" class="form-control bottom" placeholder="password goes here..."
required="required"/>
<div class="checkbox">
<label>
<input type="checkbox" name="remember-me"/> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Log in</button>
</form>
</div>
問題出在loadUserByUsername
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = repo.findOneByUserName(username);
if(user == null) {
throw new UsernameNotFoundException(username);
}
if(requireActivation && !user.getToken().equals("1")) {
Application.log.error("User [" + username + "] tried to log in, but his account is not activated.");
throw new UsernameNotFoundException(username + " did not activate his account.");
}
httpSession.setAttribute(CURRENT_USER_KEY, user);
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRole());
return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), auth);
}
您將用戶設置為會話。 不要這樣做! 只需加載用戶並將其返回。 用戶自動存儲在會話中,可以像在此答案中所示查找。 我認為密碼檢查不起作用的原因是您將BCryptPasswordEncoder
配置為密碼編碼器。 請確保您存儲在User
中的密碼由此編碼器進行編碼。 否則密碼檢查將失敗。 要避免自定義激活檢查,請使User
類實現UserDetails 。 如果您檢查文檔,則可以設置4個標志,將由spring boot檢查。
boolean isAccountNonExpired() // Indicates whether the user's account has expired.
boolean isAccountNonLocked() // Indicates whether the user is locked or unlocked.
boolean isCredentialsNonExpired() // Indicates whether the user's credentials (password) has expired.
boolean isEnabled() // Indicates whether the user is enabled or disabled.
您的loadUserByUsername
實現應該如下所示。 它真的應該只做方法名稱建議。 如果您找不到具有給定用戶名的用戶,請查找用戶並拋出UsernameNotFoundException
。
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = repo.findOneByUserName(username);
if(user == null) {
throw new UsernameNotFoundException(username);
}
return user;
}
如果您不想讓'User'實現'UserDetails'(例如,將框架和業務邏輯分開),請使用此構造函數返回Spring 用戶 ,您可以在其中設置這些標志。 您的實現可能如下所示:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = repo.findOneByUserName(username);
if(user == null) {
throw new UsernameNotFoundException(username);
}
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRole());
return new org.springframework.security.core.userdetails.User(
user.getUserName(),
user.getPassword(),
requireActivation && !user.getToken().equals("1"), // enabled. Use whatever condition you like
true, // accountNonExpired. Use whatever condition you like
true, // credentialsNonExpired. Use whatever condition you like
true, // accountNonLocked. Use whatever condition you like
auth);
}
然后,彈簧自動檢查密碼,權限,激活狀態等。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.