Java 尽管提供了正确的凭据,Spring security仍会返回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,

在配置使用嵌入式H2数据库检索用户凭据的自定义用户详细信息服务之后,我在完成post命令时不断收到401个未经授权的错误,即使用户名和密码可用。我不知道这是否有什么不同,但控制台仍然打印生成的安全密码(尽管自动生成的凭据返回相同的401错误)。请看我下面的代码,并让我知道任何可用的建议或修复

用户模型

@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();
    }
}