首页 > 解决方案 > Spring security Basic Authentication - 401 Unauthorized with correct credentials

问题描述

这是我的安全配置类,我正在使用 BCryptPasswordEncoder

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder encoder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic()
            .and()
            .authorizeRequests()
            .antMatchers(HttpMethod.POST,"/api/auth/register")
            .permitAll()
            .antMatchers(HttpMethod.GET,"/api/auth/resources")
            .hasAuthority("USER")
            .and()
            .csrf().disable();

    }

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

这是我对 UserDetailsS​​ervice 的实现

public class UserDetailsServiceImpl implements UserDetailsService{

    @Autowired
    private AccountRepository repo;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Account account = repo.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("No user found for username " + username));
        User user = 
                new User(account.getUsername(), account.getPassword(), true, true, true, true, AuthorityUtils.createAuthorityList(account.getAuthorities()));
        return user;
    }

}

上面的 POST 方法是我可以提供存储在 MySQL 表中的用户名和密码的地方。

现在,当我可以使用 Postman 使用刚刚添加的用户名和密码调用 GET 方法时,我会收到如下所示的 401 Unauthorized 错误

{
    "timestamp": "2020-05-23T20:12:10.165+0000",
    "status": 401,
    "error": "Unauthorized",
    "message": "Unauthorized",
    "path": "/api/auth/resources"
}

标签: javaspringspring-bootspring-securitybasic-authentication

解决方案


Spring Security 具有ExpressionUrlAuthorizationConfigurer.java以下方法。这里前缀ROLE_ 有所作为

  • 对于hasAuthority(), hasAnyAuthority()方法,我们需要使用前缀ROLE_来传递权限,即ROLE_USER

  • forhasRole()方法自动添加前缀ROLE_,因此我们只能将权限名称传递为USER


private static String hasRole(String role) {
    Assert.notNull(role, "role cannot be null");
    if (role.startsWith("ROLE_")) {
        throw new IllegalArgumentException("role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
    } else {
        return "hasRole('ROLE_" + role + "')";
    }
}

private static String hasAuthority(String authority) {
    return "hasAuthority('" + authority + "')";
}

private static String hasAnyAuthority(String... authorities) {
    String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','");
    return "hasAnyAuthority('" + anyAuthorities + "')";
}

推荐阅读