当前位置: 首页 > 知识库问答 >
问题:

hasRole始终返回403

夏侯博
2023-03-14

我的安全配置似乎不正确。无论我在使用hasRole时做什么,我的endpoint总是返回403。

此外,除非我在这两个下复制我的antMatchers,否则我无法得到任何东西。requestMatchers()。authorizeRequests()。很明显,我遗漏了一些东西。

基本上,我希望所有内容都需要身份验证,但只有当用户是某些组的成员时(现在只需要admin),少数endpoint才可以访问。

我的安全配置如下。hasRole旁边的一切都有效。

@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .requestMatchers()
                .antMatchers(HttpMethod.GET, "/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html")
                .antMatchers(HttpMethod.GET, "/users")
                .and()
            .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html").permitAll()
                .antMatchers(HttpMethod.GET, "/users").hasRole("ADMIN")    
                .anyRequest().authenticated();
    }

    // Inspiration: https://spring.io/blog/2015/06/08/cors-support-in-spring-framework#comment-2416096114
    @Override
    public void configure(WebSecurity web) throws Exception {
        web
            .ignoring()
                .antMatchers(HttpMethod.OPTIONS, "/**");
    }
}

我的AuthenticationConfiguration如下

@Configuration
@EnableResourceServer
public class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
    private final UserDetailsService userService;
    private final PasswordEncoder passwordEncoder;

    public AuthenticationConfiguration(UserDetailsService userService, PasswordEncoder passwordEncoder) {
        this.userService = userService;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userService)
                .passwordEncoder(passwordEncoder);
    }
}

我的AuthorizationServerConfiguration如下

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    private final AuthenticationManager authenticationManager;

    public AuthorizationServerConfiguration(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
                .inMemory()
                .withClient("html5")
                .secret("password")
                .authorizedGrantTypes("password")
                .scopes("openid");
    }
}

我很乐意发布我的用户服务和其他东西。但除了hasRole主体之外,一切似乎都可以工作,并加载了正确的权限(角色)。但请让我知道我是否应该发布更多代码。

完整的源代码可以在这里找到。

共有3个答案

夹谷浩宕
2023-03-14

我也有同样的问题,只是忘记了从UserDetails(SpringSecurity类)实现getAuthorities()方法。查看我的实体:

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Entity
@Table(name = "tb_user")
public class User implements UserDetails, Serializable {

private static final long serialVersionUID = -6519124777839966091L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;

@Column(unique = true)
private String email;
private String password;

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
        name = "tb_user_role",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();

public User() {
}

public User(Long id, String firstName, String lastName, String email, String password) {
    this.id = id;
    this.firstName = firstName;
    this.lastName = lastName;
    this.email = email;
    this.password = password;
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public void setPassword(String password) {
    this.password = password;
}

public Set<Role> getRoles() {
    return roles;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    return roles.stream().map(role -> new SimpleGrantedAuthority(role.getAuthority()))
            .collect(Collectors.toList());
}

public String getPassword() {
    return password;
}

@Override
public String getUsername() {
    return email;
}

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

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

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

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


@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    User user = (User) o;
    return Objects.equals(id, user.id);
}

@Override
public int hashCode() {
    return Objects.hash(id);
}
}

默认情况下,getAuthorities方法返回null当您从安全包扩展UserDetails类时,您需要实现如下内容:

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    return roles.stream().map(role -> new SimpleGrantedAuthority(role.getAuthority()))
        .collect(Collectors.toList());
}

我希望这能帮助到别人,对不起我的英语错误!呵呵

李鸿
2023-03-14

继我对这个问题的评论之后,我将提供用于测试的OAuth2配置类示例。我总是使用两种不同的webapp,因为我想在auth-server和resource-server之间有一条清晰的界限(而且这会使配置变得更加困难……),因此,我的示例在单个webapp中使用时可能需要进行一些调整。

身份验证服务器的配置:

@EnableAuthorizationServer
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    private TokenStore tokenStore;
    private DataSource dataSource;

    @Autowired
    public OAuth2Config(TokenStore tokenStore,
                        DataSource dataSource) {
        this.tokenStore = tokenStore;
        this.dataSource = dataSource;
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore);
    }


    @Configuration
    public static class TokenStoreConfiguration {
        @Bean
        public TokenStore tokenStore(DataSource dataSource) {
            return new JdbcTokenStore(dataSource);
        }
    }
}

资源服务器的配置:

@EnableResourceServer
@Configuration
public class OAuth2Config extends ResourceServerConfigurerAdapter {
    public static final String PROPERTY_RESOURCE_ID = "com.test.oauth.resourceId";

    private Environment environment;
    private TokenStore tokenStore;

    @Autowired
    public OAuth2Config(Environment environment,
                        TokenStore tokenStore) {
        this.environment = environment;
        this.tokenStore = tokenStore;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.tokenStore(tokenStore)
                .resourceId(environment.getProperty(PROPERTY_RESOURCE_ID))
                .stateless(true);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/demo")
                    .access("hasRole('DEMO')")

                .anyRequest().denyAll()
                .and()
                .formLogin().disable()
                .logout().disable()
                .jee().disable()
                .x509().disable();
    }

    @Configuration
    public static class TokenStoreConfiguration {
        @Bean
        public TokenStore tokenStore(DataSource dataSource) {
            return new JdbcTokenStore(dataSource);
        }
    }
}

显然,这需要配置一个数据源bean。此实现使用了spring security OAuth2提供的默认表(它们远非理想的,但可以根据需要进行自定义)。

您可能需要根据您的情况调整一些内容(如果人们可能想将其与JDBC一起使用,我将保留我提供的类作为参考):

  1. 仅创建一个类型为TokenStore的bean,并在MemoryTokenstore中使用,而不是JdbcTokenStore

编辑:看到ritesh.garg的答案,我认为我提供的可能无法解决您的问题,但可能有助于一些人弄清楚在哪里以及如何开始配置Spring Security OAuth2(当我第一次这样做时,我发现很难做到,因为那时我找不到任何清晰的示例,尽管这可能已经改变了)

华振
2023-03-14

你试过用“ROLE_ADMIN”而不仅仅是“ADMIN”吗?看看这个作为参考:

Spring security在所有角色名称中添加了前缀“ROLE\uu”?

 类似资料:
  • 我试图根据角色限制对endpoint的访问。我在stackoverflow上搜索了一个解决方案,尝试了一些,但没有成功地解决我的问题。我尝试在全局配置(WebSecurityConfig)和预授权注释中进行限制,调用时都返回403。我的测试用户拥有SYS_ADMIN角色,我已经验证了这个流,它实际上拥有这个角色。以下是我的消息来源。 全球网络安全配置 人员控制员 榜样

  • 问题内容: 我以前使用过媒体播放器,但从未遇到过此问题。每当我尝试使用MediaPlayer.create()时,该方法都会使我为null,并且无法播放声音。有什么我想念的吗? 我的sound.mp3在我的原始文件夹中,通过将声音拖到eclipse中的文件夹中,我将其放置在其中。请帮忙,因为我以前玩过声音,所以这真的困扰我:( 问题答案: 如果create() API由于某种原因失败,则返回nul

  • 问题内容: 尽管是有效的类,但以下代码会打印。 文档说方法返回 由 aClassName 命名的类对象,或者如果当前没有加载该名称的类。如果 aClassName 为,则返回。 我也试图获得当前的viewcontroller已加载但仍然得到 可能是什么问题? 更新: 即使尝试这样做,我仍然可以 问题答案: 该函数 确实 适用于(纯和Objective-C派生的)swift类,但是仅当您使用全限定名

  • 问题内容: 我觉得有点愚蠢,但它不起作用: 我有如果给定的用户是unicode。如果字符串中包含或,我想打印成功,但是我总是得到的结果。 问题答案: 隐式锚定到字符串的开头。如果要在字符串中搜索可以在字符串中任何位置的子字符串,则需要使用: 输出: 另外,Python Regexes不需要在开头和结尾都有一个。 最后,我添加到该行的末尾,因为我认为这就是您想要的。否则,您会得到类似的信息,但并不太

  • 我正在尝试使用NSKeyDarchiver在应用程序关闭和运行周期之间存储数据。我试图存储的根对象是一个NSMutableArray,但在这个对象中有基础对象和自定义对象的集合(所有这些都符合NSCoding)。 文件保存代码如下 该文件保存fine并且不会抛出异常。再次启动应用程序时,使用以下代码恢复该文件。 在这一点上,sessionData总是为零,而pData是几千字节长的,因此我知道问题

  • 我有以下异常处理程序: 此代码应该包装异常并返回具有正确状态代码的ResponseEntity。