春季安全性登录失败,尽管用户名和密码正确。

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

Spring Security login fails despite correct username and password

问题

以下是您提供的内容的翻译:

早上好,我在使用Spring Security的应用程序中遇到了登录问题。每次我尝试登录(即使用户名和密码是正确的),应用程序都会将我重定向到失败的URL(在我的情况下是:/login?error=true)。密码使用BCrypt进行加密,并且我在使用MySQL数据库存储它们。

该应用程序基于《Spring in Action 5》中的代码:
https://github.com/habuma/spring-in-action-5-samples/tree/master/ch04/tacos

我的代码:

User类

@Entity
@Data
@NoArgsConstructor
@Table(name = "Users")
public class User implements UserDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String email;

    public User(String username, String password, String email) {
        this.username = username;
        this.password = password;
        this.email = email;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return false;
    }

}

安全配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Qualifier("userService")
    @Autowired
    private UserDetailsService userDetailsService;

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

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

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.authorizeRequests()
                .antMatchers("/calendar")
                    .hasRole("USER")
                .antMatchers("/", "/**").permitAll()
                .and()
                    .formLogin()
                        .loginPage("/login")
                        .defaultSuccessUrl("/calendar")
                        .failureUrl("/login?error=true")
                .and()
                    .logout()
                        .logoutSuccessUrl("/");
    }

}

用户服务

@Service
public class UserService implements UserDetailsService {

    private UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository){
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if(user != null){
            return user;
        }
        throw new UsernameNotFoundException("Username not found: " + username);
    }
}

控制器

@Controller
@RequestMapping("/register")
public class UserController {

    private UserRepository userRepository;
    private PasswordEncoder passwordEncoder;

    @Autowired
    public UserController(UserRepository userRepository, PasswordEncoder passwordEncoder){
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    @ModelAttribute
    public void calendar(Model model){
        model.addAttribute("user", new User());
    }

    @GetMapping
    public String register(){
        return "register";
    }

    @PostMapping
    public String addUser(@ModelAttribute User user){
        User newUser = new User(user.getUsername(),passwordEncoder.encode(user.getPassword()),user.getEmail());
        userRepository.save(newUser);
        return "redirect:/login";
    }

}

登录表单(Thymeleaf)

<form th:method="POST" th:action="@{/login}">
    <div class="formInputs">
        <label for="username">Username</label>
        <input id="username" name="username" type="text">
    </div>
    <div class="formInputs">
        <label for="password">Password</label>
        <input id="password" name="password" type="password">
    </div>
    <div style="clear: both"></div>
    <input type="submit" value="Log in">
</form>

注册表单

<form method="POST" th:action="@{/register}" th:object="${user}">
    <div class="formInputs">
        <label for="username">Username</label>
        <input id="username" type="text" th:field="*{username}">
    </div>
    <div class="formInputs">
        <label for="password">Password</label>
        <input id="password" type="password" th:field="*{password}">
    </div>
    <div class="formInputs">
        <label for="email">Email</label>
        <input id="email" type="email" th:field="*{email}">
    </div>
    <div style="clear: both"></div>
    <input type="submit" value="Register">
    <input type="reset" value="Reset">
</form>

如果有人能帮助我找到解决方案,我将不胜感激,提前谢谢您。

英文:

Good morning, I have encountered problem with logging into app which uses Spring Security. Every time i try to log in (even though username and password are correct), app redirects me to failure url (in my case it's: /login?error=true). Passwords are encrypted with BCrypt and I'm using MySQL Database to store them.

App is based on code from Spring in Action 5:
<https://github.com/habuma/spring-in-action-5-samples/tree/master/ch04/tacos>

My code:

User class

@Entity
@Data
@NoArgsConstructor
@Table(name = &quot;Users&quot;)
public class User implements UserDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String email;

    public User(String username, String password, String email) {
        this.username = username;
        this.password = password;
        this.email = email;
    }

    @Override
    public Collection&lt;? extends GrantedAuthority&gt; getAuthorities() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return false;
    }

}

Security configuration

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Qualifier(&quot;userService&quot;)
    @Autowired
    private UserDetailsService userDetailsService;

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

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

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.authorizeRequests()
                .antMatchers(&quot;/calendar&quot;)
                    .hasRole(&quot;USER&quot;)
                .antMatchers(&quot;/&quot;,&quot;/**&quot;).permitAll()
                .and()
                    .formLogin()
                        .loginPage(&quot;/login&quot;)
                        .defaultSuccessUrl(&quot;/calendar&quot;)
                        .failureUrl(&quot;/login?error=true&quot;)
                .and()
                    .logout()
                        .logoutSuccessUrl(&quot;/&quot;);
    }

}

User service

@Service
public class UserService implements UserDetailsService {

    private UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository){
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if(user != null){
            return user;
        }
        throw new UsernameNotFoundException(&quot;Username not found: &quot;+username);
    }
}

Controller

@Controller
@RequestMapping(&quot;/register&quot;)
public class UserController {

    private UserRepository userRepository;
    private PasswordEncoder passwordEncoder;

    @Autowired
    public UserController(UserRepository userRepository, PasswordEncoder passwordEncoder){
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    @ModelAttribute
    public void calendar(Model model){
        model.addAttribute(&quot;user&quot;, new User());
    }

    @GetMapping
    public String register(){
        return &quot;register&quot;;
    }

    @PostMapping
    public String addUser(@ModelAttribute User user){
        User newUser = new User(user.getUsername(),passwordEncoder.encode(user.getPassword()),user.getEmail());
        userRepository.save(newUser);
        return &quot;redirect:/login&quot;;
    }

}

Login form (Thymeleaf)

    &lt;form th:method=&quot;POST&quot; th:action=&quot;@{/login}&quot;&gt;
        &lt;div class=&quot;formInputs&quot;&gt;
            &lt;label for=&quot;username&quot;&gt;Username&lt;/label&gt;
            &lt;input id=&quot;username&quot; name=&quot;username&quot; type=&quot;text&quot;&gt;
        &lt;/div&gt;
        &lt;div class=&quot;formInputs&quot;&gt;
            &lt;label for=&quot;password&quot;&gt;Password&lt;/label&gt;
            &lt;input id=&quot;password&quot; name=&quot;password&quot; type=&quot;password&quot;&gt;
        &lt;/div&gt;
        &lt;div style=&quot;clear: both&quot;&gt;&lt;/div&gt;
        &lt;input type=&quot;submit&quot; value=&quot;Log in&quot;&gt;
    &lt;/form&gt;

Registration form

&lt;form method=&quot;POST&quot; th:action=&quot;@{/register}&quot; th:object=&quot;${user}&quot;&gt;
            &lt;div class=&quot;formInputs&quot;&gt;
                &lt;label for=&quot;username&quot;&gt;Username&lt;/label&gt;
                &lt;input id=&quot;username&quot; type=&quot;text&quot; th:field=&quot;*{username}&quot;&gt;
            &lt;/div&gt;
            &lt;div class=&quot;formInputs&quot;&gt;
                &lt;label for=&quot;password&quot;&gt;Password&lt;/label&gt;
                &lt;input id=&quot;password&quot; type=&quot;password&quot; th:field=&quot;*{password}&quot;&gt;
            &lt;/div&gt;
            &lt;div class=&quot;formInputs&quot;&gt;
                &lt;label for=&quot;email&quot;&gt;Email&lt;/label&gt;
                &lt;input id=&quot;email&quot; type=&quot;email&quot; th:field=&quot;*{email}&quot;&gt;
            &lt;/div&gt;
            &lt;div style=&quot;clear: both&quot;&gt;&lt;/div&gt;
            &lt;input type=&quot;submit&quot; value=&quot;Register&quot;&gt;
            &lt;input type=&quot;reset&quot; value=&quot;Reset&quot;&gt;
        &lt;/form&gt;

If someone could help me find a solution i would be grateful, thank you in advance.

答案1

得分: 0

确保您的用户返回enabled = true,以及isAccountNonExpired = true(以及所有其他属性,比如isAccountNonLocked)。同时返回一个空权限列表,而不是null。

否则,Spring Security将视您的用户为已禁用/已锁定/其他状态,不允许您登录。

英文:

Make sure your user returns enabled = true, as well as isAccountNonExpired = true (and all others as well, like isAccountNonLocked). Also return an empty list of authorities, not null.

Otherwise Spring Security will treat your user as disabled/locked/whatever and not allow you to login.

huangapple
  • 本文由 发表于 2020年4月10日 20:42:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/61140489.html
匿名

发表评论

匿名网友

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

确定