Java 尽管提供了正确的凭据,Spring security仍会返回401未经授权的代码
在配置使用嵌入式H2数据库检索用户凭据的自定义用户详细信息服务之后,我在完成post命令时不断收到401个未经授权的错误,即使用户名和密码可用。我不知道这是否有什么不同,但控制台仍然打印生成的安全密码(尽管自动生成的凭据返回相同的401错误)。请看我下面的代码,并让我知道任何可用的建议或修复 用户模型Java 尽管提供了正确的凭据,Spring security仍会返回401未经授权的代码,java,spring-security,Java,Spring Security,在配置使用嵌入式H2数据库检索用户凭据的自定义用户详细信息服务之后,我在完成post命令时不断收到401个未经授权的错误,即使用户名和密码可用。我不知道这是否有什么不同,但控制台仍然打印生成的安全密码(尽管自动生成的凭据返回相同的401错误)。请看我下面的代码,并让我知道任何可用的建议或修复 用户模型 @Entity public class ApplicationUser { @Id private Long id; private String username,
@Entity
public class ApplicationUser {
@Id
private Long id;
private String username, password, role;
public ApplicationUser(String username, String role, String password) {
this.username=username;
this.password=password;
this.role=role;
}
public ApplicationUser() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public String toString() {
return "ApplicationUser{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", role='" + role + '\'' +
'}';
}
}
用户存储库类
@Repository
public class AppUserRepository {
@Autowired
JdbcTemplate jdbcTemplate;
static class ApplicationUserRowMapper implements RowMapper<ApplicationUser> {
@Override
public ApplicationUser mapRow(ResultSet rs, int rowNum) throws SQLException {
ApplicationUser applicationUser = new ApplicationUser();
applicationUser.setUsername(rs.getString("username"));
applicationUser.setPassword(rs.getString("password"));
applicationUser.setRole(rs.getString("userrole"));
return applicationUser;
}
}
public List<ApplicationUser> findAll() {
return jdbcTemplate.query("select u.username, u.password, ur.userrole from ApplicationUsers u, ApplicationUsers_Role ur where u.username = ur.username",
new ApplicationUserRowMapper());
}
public ApplicationUser findByUsername(String username) {
return jdbcTemplate.queryForObject("select u.username, u.password, ur.userrole from ApplicationUsers u, ApplicationUsers_Role ur where u.username = ? and u.username = ur.username",
new Object[] {username}, new ApplicationUserRowMapper());
}
}
自定义身份验证提供程序
@Service
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
AppUserRepository userRepository;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
ApplicationUser user = userRepository.findByUsername(name);
if(user == null) {
throw new BadCredentialsException("Authentication failed.");
}
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(new SimpleGrantedAuthority(user.getRole()));
return new UsernamePasswordAuthenticationToken(name, password, grantedAuthorities);
}
@Override
public boolean supports(Class<?> aClass) {
return aClass.equals(UsernamePasswordAuthenticationToken.class);
}
}
更新一::
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private AppUserRepository userRepo;
@Override
public UserDetails loadUserByUsername(String username) {
ApplicationUser user = userRepo.findByUsername(username);
if(user == null) {
throw new UsernameNotFoundException("User '" + username + "' not found.");
}
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(user.getRole());
return new User(user.getUsername(), user.getPassword(), Collections.singletonList(grantedAuthority));
}
}
我可以通过删除我的自定义身份验证类(虽然我不认为这实际上是问题的一部分)并编辑我的web安全配置以匹配以下内容来纠正这个问题
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = package_location)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public CustomUserDetailsService detailsService;
@Bean
public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
@Autowired
public void configureGlobal (AuthenticationManagerBuilder auth) throws Exception {
//the password encoder here is only to support a mix of encoding - that change can be removed
auth.userDetailsService(detailsService).passwordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.frameOptions()
.disable()
.and()
.authorizeRequests()
.antMatchers("/awsorchestrator/**")
.hasAnyRole("ADMIN", "USER")
.and()
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.and()
.csrf()
.disable();
}
}
与我的问题直接相关的重要部分是PasswordEncoderFactorys.createDelegatingPasswordEncoder()部分。我还必须将存储在数据库中的密码更改为前缀为{bcrypt},现在我可以毫无问题地登录了
感谢R.G提供的提示。我应该注意,h2 db中存储的密码是使用BCrypt加密的。此外,我还手动测试了存储库方法,以确保它们返回用户并且也能正常工作。根据代码,使用
AppUserRepository
获取详细信息。CustomUserDetailsService
中的逻辑是什么?请参阅更新一。谢谢@R.GI刚刚注意到您没有在验证时比较密码。忽略我之前的评论请允许您设置logging.level.org.springframework.security=debug
并检查出了什么问题请您解释一下为什么数据库中的密码必须以{bcrypt}作为前缀?它告诉安全性这是一个bcrypt编码的密码,因为我们在密码编码器配置中没有指定它。
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private AppUserRepository userRepo;
@Override
public UserDetails loadUserByUsername(String username) {
ApplicationUser user = userRepo.findByUsername(username);
if(user == null) {
throw new UsernameNotFoundException("User '" + username + "' not found.");
}
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(user.getRole());
return new User(user.getUsername(), user.getPassword(), Collections.singletonList(grantedAuthority));
}
}
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = package_location)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public CustomUserDetailsService detailsService;
@Bean
public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
@Autowired
public void configureGlobal (AuthenticationManagerBuilder auth) throws Exception {
//the password encoder here is only to support a mix of encoding - that change can be removed
auth.userDetailsService(detailsService).passwordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.frameOptions()
.disable()
.and()
.authorizeRequests()
.antMatchers("/awsorchestrator/**")
.hasAnyRole("ADMIN", "USER")
.and()
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.and()
.csrf()
.disable();
}
}