簡體   English   中英

Spring Boot / Spring Security,登錄表單,密碼檢查

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM