spring-security 与角色安全端点交换未经授权的restTemplate

3duebb1j  于 2022-11-11  发布在  Spring
关注(0)|答案(1)|浏览(162)

我正在尝试将Spring安全性添加到我的Rest API并保护其中一个端点。我将实现UserDetails和RoleEntity的UserEntity添加到Rest API。它们存在于数据库中,并且用户具有角色:

public class UserEntity implements UserDetails {
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
@Column(name="id")
private String id;
private String name;
private String password;
@ManyToMany
@JoinTable(
        name = "user_roles",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<RoleEntity> roles;

并覆盖UserDetails中的必要方法,并将它们设置为true。

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<SimpleGrantedAuthority> authorities = new ArrayList<>();
    for (RoleEntity role : getRoles()) {
        authorities.add(new SimpleGrantedAuthority(role.getName()));
    }
    return authorities;
}

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

@Override
public String getPassword() {
    return password;
}

在扩展WebSecurityConfigurerAdapter的MyWebSecurityConfig中添加了配置:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers("/offences", "/offences/*", "/offences/**").hasRole("ADMIN")
            .anyRequest().permitAll()
            .and()
            .httpBasic();
}

而且它也在工作。端点是安全的。但是当我在其他应用程序中硬编码一些用户(使用“管理员”用户名和密码)来发送请求时:

public HashMap<Boolean, Object> find(FindOffenceForm findOffenceForm) {

    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setBasicAuth("admin", "admin");

    HttpEntity<String> request = new HttpEntity<>(httpHeaders);
    try {
        ResponseEntity<String> responseEntity = restTemplate.exchange(URL_OFFENCE + "/find/" + findOffenceForm.getName(),
                HttpMethod.GET, request, String.class);
        result.put(true, objectMapper.readValue(responseEntity.getBody(), new TypeReference<Set<OffenceDTO>>() {
        }));
    } catch (Exception ex) {
        result.put(false, ex.getMessage());
    }
  • 我得到401未经授权,在我的API中,我可以看到消息警告13660 o.s.s.c.bcrypt.bCryptPasswordEncoder:编码后的密码看起来不像BCrypt。在resttemaplete中发送请求时,我应该为BCrypt编码密码吗?*
    编辑:好的,所以在我的数据库中,我没有为bcrypt编码密码。我更改了它,现在我得到403禁止。我添加到config .csrf().and().cors().disabled,但没有任何更改。
dffbzjpn

dffbzjpn1#

我想你可能会看到403状态码,因为ExpressionUrlAuthorizationConfigurer.AuthorizedUrl.hasRole(String role)方法会自动将“ROLE_”前缀添加到字符串参数(请参阅此处的文档),所以过滤器链需要“ROLE_ADMIN”角色名称,而不仅仅是你传递给方法的“ADMIN”。如果你的RoleEntity.getRoles()返回“ADMIN”、“USER”等没有任何前缀的角色名称,这种情况可能会发生。
如果这就是原因,并且您不希望出现此默认行为,则有3种选择:
1.使用方法.hasAuthority(String authority)代替,如javadoc中所建议;
1.在UserEntity类中重写getAuthorities()方法中重写GrantedAuthority创建逻辑。
例如,像这样:

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<SimpleGrantedAuthority> authorities = new ArrayList<>();
    for (RoleEntity role : getRoles()) {
        authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
    }
    return authorities;
}

1.注册一个不带前缀的GrantedAuthorityDefaults类型的Bean,如下所示:
比如像这样。

@Bean
public GrantedAuthorityDefaults grantedAuthorityDefaults() {
    return new GrantedAuthorityDefaults("");
}

相关问题