Spring security Basic Authentication - 401 Unauthorized with correct credentials

Posted

技术标签:

【中文标题】Spring security Basic Authentication - 401 Unauthorized with correct credentials【英文标题】: 【发布时间】:2020-09-10 15:50:09 【问题描述】:

这是我的安全配置类,我正在使用 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"

【问题讨论】:

你使用的用户是否有"USER"权限,尝试用authenticed()替换hasAuthority("USER") .hasAuthority("USER") 替换为.hasAuthority("ROLE_USER") 并确保将角色存储在数据库中为ROLE_ROLENAMEROLE_USER @Ehab 您是否尝试过给出的答案? 【参考方案1】:

Spring Security 有ExpressionUrlAuthorizationConfigurer.java,其方法如下。这里的前缀 ROLE_ 有所不同。

对于hasAuthority(), hasAnyAuthority()方法,我们需要通过前缀ROLE_的权限,即ROLE_USER

对于hasRole()方法自动添加前缀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 + "')";

【讨论】:

以上是关于Spring security Basic Authentication - 401 Unauthorized with correct credentials的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security 配置:Basic Auth + Spring Cloud Gateway

Spring Security应用开发(04)HTTP basic认证

为啥 Spring boot Security Basic Authentication 慢?

Spring boot security rest basic Authentication example

spring-boot Actuator 连同 Spring Security 和 Form Basic Auth

Spring security Basic Authentication - 401 Unauthorized with correct credentials