Woj*_*zuk 4 java spring spring-security spring-boot
我有一个可能很容易的问题,但我不明白。
我对 Spring Boot 不是很熟悉,很多事情在这里自动发生。我想检查数据库中是否存在在表单中写入用户名和密码的人[并且他的帐户已激活]。用户数据存储在 application.properties 中配置的 MySQL 数据库中。我想检查“用户”表中是否存在提供用户名的人,并检查提供的密码是否等于数据库中的用户密码。目前我可以从数据库中输入任何用户名,密码可以是随机的(这对我来说很明显,因为我不会在任何地方检查它,而且很奇怪,因为我觉得周围的一切都说它工作正常)。这对我来说听起来很简单,但我在 StackOverflow 或教程上找不到任何合适的解决方案。
我的一般问题是 - 我应该在哪里以及如何从登录表单中检查密码?它是自动完成的(但它以某种方式不起作用),还是应该编写我的自定义控制器/service/method 来做到这一点?如果需要自定义控制器,那么我解决问题的方向应该是什么?
目前我不知道该去哪里。我希望与我的问题相关的所有剩余代码都粘贴在这里。预先感谢您提供的所有提示和评论。
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());
}
Run Code Online (Sandbox Code Playgroud)
用户服务类:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
用户控制器:
@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";
}
}
Run Code Online (Sandbox Code Playgroud)
登录表格:
<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>
Run Code Online (Sandbox Code Playgroud)
问题出在你的 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);
}
Run Code Online (Sandbox Code Playgroud)
您将用户设置为会话。不要这样做!只需加载用户并返回它。用户自动存储在会话中,可以像本答案中所示那样进行查找。我认为密码检查不起作用的原因是您配置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.
Run Code Online (Sandbox Code Playgroud)
你的实现loadUserByUsername应该是这样的。它真的应该只做方法名称所暗示的。查找用户并在UsernameNotFoundException找不到具有给定用户名的用户时抛出一个。
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = repo.findOneByUserName(username);
if(user == null) {
throw new UsernameNotFoundException(username);
}
return user;
}
Run Code Online (Sandbox Code Playgroud)
如果您不想让您的“用户”实现“用户详细信息”(例如将框架和业务逻辑分开),请使用此构造函数返回 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);
}
Run Code Online (Sandbox Code Playgroud)
spring 会自动检查密码、权限、激活状态等。
| 归档时间: |
|
| 查看次数: |
9909 次 |
| 最近记录: |