首页 > 解决方案 > Spring Security - 即使凭据良好,登录也会失败

问题描述

我对 spring 和 spring security 有点陌生。我一直在尝试使用 Spring Security 实现具有身份验证/授权的基本登录,我一直在关注网络上的几个教程,但没有一个真正帮助我。当我尝试使用数据库中的用户登录时,它给了我错误:凭据错误

这是我使用的代码:用户/角色/权限实体

@Entity
public class User {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "user_id")
private int id;
private String name;
private String email;
private String password;
private String usual_IP;
private int logged;
@ManyToMany
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private List<Role> roles;

角色

@Entity
public class Role {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "role_id")
private int id;
private String name;
private String description;
@ManyToMany(mappedBy = "roles")
@JsonIgnore
private List<User> users;

特权

@Entity
public class Privilege {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "Privilege_id")
private int id;
private String name;
@ManyToMany(mappedBy = "privileges")
private List<Role> roles;

这是弹簧配置

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private DataSource dataSource;

@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
    return new BCryptPasswordEncoder();
}

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

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.
            authorizeRequests()
            .antMatchers("/", "/login", "/logout").permitAll()
            .antMatchers("/users").permitAll()
            .antMatchers("/user/").permitAll()
            .antMatchers("/user/**").permitAll()
            .antMatchers("/users/**").permitAll()
            .antMatchers("/roles").permitAll()
            .antMatchers("/role").permitAll()
            .antMatchers("/role/**").permitAll()
            .antMatchers("/userInfo").access("hasAnyRole('USER', 'ADMIN')")
            .antMatchers("/admin").access("hasRole('ADMIN')")
            .anyRequest().authenticated().and().csrf().disable().formLogin()
            .and().exceptionHandling().accessDeniedPage("/403")
            .and().formLogin()//
            .loginProcessingUrl("/j_spring_security_check")
            .loginPage("/login")//
            .defaultSuccessUrl("/userAccountInfo")//
            .failureUrl("/login?error=true")//
            .usernameParameter("name")//
            .passwordParameter("password")
        .and().logout().logoutUrl("/logout").logoutSuccessUrl("/logoutSuccessful")
            .and().exceptionHandling();


}

这里是 usersDetailsS​​ervice 的实现

 @Service
 public class UserDetailsServiceImpl implements UserDetailsService {

@Autowired
private UserRepository userRepository;

@Override
@Transactional
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {

    User user = userRepository.findByName(name);

    if(user==null) {throw new UsernameNotFoundException("No such user: " + name);
    } else if (user.getRoles().isEmpty()) {
        throw new UsernameNotFoundException("User " + name + " has no authorities");
    }
    UserDetailsAdapter userToAdapt = new UserDetailsAdapter(user);
    return userToAdapt;
}

}

userDetails 实现

public class UserDetailsAdapter implements UserDetails {

private User user;

public UserDetailsAdapter(User user) {this.user = user;}

public User getAccount() {return user;}

public Integer getId(){return user.getId();}

public String getEmail () {return user.getEmail();}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<GrantedAuthority> authorities= new ArrayList<>();

    for (Role role: user.getRoles()) {
        authorities.add(new SimpleGrantedAuthority(role.getName()));
        role.getPrivileges().stream().map(p -> new SimpleGrantedAuthority(p.getName())).forEach(authorities::add);
    }

    return authorities;
}

@Override
public String getPassword() {
    return user.getPassword();
}

@Override
public String getUsername() {
    return user.getName();
}

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

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

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

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

登录控制器

@RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage(Model model) {

    return "loginPage";
}

@RequestMapping(value = "/userInfo", method = RequestMethod.GET)
public String userInfo(Model model, User user) {

    // After user login successfully.
    String userName = user.getName();

    System.out.println("User Name: " + userName);

    User loginedUser = user;

    String userInfo = user.toString();
    model.addAttribute("userInfo", userInfo);

    return "userInfoPage";
}

还有百里香模板

<!-- /login?error=true -->
<div th:if="${#request.getParameter('error') == 'true'}"
 style="color:red;margin:10px 0px;">
Login Failed!!!<br />
Reason :
<span th:if="${#session!= null and 
#session.getAttribute('SPRING_SECURITY_LAST_EXCEPTION') != null}"



th:utext="${#session.getAttribute
('SPRING_SECURITY_LAST_EXCEPTION').message}">
            Static summary
     </span>

</div>

<h3>Enter user name and password:</h3>
<form name='f' th:action="@{/j_spring_security_check}" method='POST'>
<table>
    <tr>
        <td>User:</td>
        <td><input type='text' name='name' value=''></td>
    </tr>
    <tr>
        <td>Password:</td>
        <td><input type='password' name='password' /></td>
    </tr>
    <tr>
        <td>Remember Me?</td>
        <td><input type="checkbox" name="remember-me" /></td>
    </tr>
    <tr>
        <td><input name="submit" type="submit" value="submit" /></td>
    </tr>
</table>
</form>

编辑

这是将用户保存到数据库中并对密码进行编码的服务

    @Override
public void saveUser(User user) {

    user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
    userRepository.save(user);
}

这是我用来通过邮递员手动将新用户添加到数据库中的控制器

@RequestMapping(value = "/users", method = RequestMethod.POST)
public ResponseEntity<Void> createUser(@RequestBody User user, UriComponentsBuilder ucBuilder) {


    if (userServices.isUserExist(user)) {

        return new ResponseEntity(new CustomErrorType("Unable to create. A User with name " +
                user.getName() + " already exist."),HttpStatus.CONFLICT);
    }
    userServices.saveUser(user);

    HttpHeaders headers = new HttpHeaders();
    headers.setLocation(ucBuilder.path("/api/user/{id}").buildAndExpand(user.getId()).toUri());
    return new ResponseEntity<>(headers, HttpStatus.CREATED);

}

有人可以帮忙,我无法查明错误,非常感谢

标签: javaspring-bootspring-security

解决方案


我找到了问题的答案,我对密码进行了两次编码,因此当他们比较两个密码时,他们从未匹配过。感谢所有帮助过的人


推荐阅读