如何正确使用Spring Security中的hasRole?

问题描述 投票:0回答:4

嗨,我想要实现的是保护只有一个角色可以访问它的网址,当我尝试添加 .hasRole("USER") 时,另一个角色仍然可以访问它。这是我的做法:

这是我的控制器:

@RestController
@RequestMapping("/couponapi")
public class CouponController {

    @Autowired
    CouponRepository couponRepository;

    @PostMapping("/coupons")
    public Coupon save(@RequestBody Coupon coupon) {
        return couponRepository.save(coupon);
    }

    @GetMapping("/coupons/{code}")
    public Coupon findByCode(@PathVariable("code") String code) {
        return couponRepository.findByCode(code);
    }

    @GetMapping("/something")
    public Coupon findByCodeX() {
        return couponRepository.findByCode("SUPERSALE");
    }

}

我只想保护

@GetMapping("/something")
只用于 ROLE_ADMIN,这是我的 Spring Security 配置的样子:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailServiceImpl userDetailService;

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

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.httpBasic();
    http.authorizeRequests()
            .antMatchers(HttpMethod.GET,"/couponapi/coupons/**").hasRole("USER")
            .antMatchers(HttpMethod.POST,"/couponapi/coupons/**").hasRole("USER")
            .antMatchers("/couponapi/something").hasRole("ADMIN")
            .antMatchers("/**").authenticated()
            .and().httpBasic().and().csrf().disable();
}

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

这是我的角色课程:

@Data
@EqualsAndHashCode(of = "id")
@ToString(of = { "id" })
@Entity
public class Roles implements GrantedAuthority {

    private static final long serialVersionUID = -7314956574144971210L;

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

    private String name;

    @ManyToMany(mappedBy = "roles")
    private Set<Users> users;

    @Override
    public String getAuthority() {
        return null;
    }
}

这是我实现 UserDetailsService 类的服务:

@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        Users users = userRepository.findByEmail(s);


        if(users == null) {
            throw new UsernameNotFoundException("Username Not Found");
        }

        return new User(users.getEmail(), users.getPassword(), users.getRoles());
    }
}

这是我的数据库角色数据:

如你所见,我有 ROLE_USER 和 ROLE_ADMIN

这是我加入的数据库

** 我刚刚更新了我的问题,我已经回答了一半的问题,请阅读下面我的答案以查看最新一期

java spring spring-boot spring-security spring-data
4个回答
2
投票

在 Spring Security 中,首先定义最严格的规则,因此您的配置应该如下所示

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.httpBasic();
    http.authorizeRequests()
            .antMatchers(HttpMethod.GET,"/**/something").hasRole("USER")
            .antMatchers("/**").authenticated()               
            .and().httpBasic().and().csrf().disable();
}

0
投票

我在这里找到了罪魁祸首,但不完全是我仍然缺少 HttpMethod 的功能。这是我修复角色的方法,在我的 Role 类中,我犯了一个错误,我试图实现 GrantedAuthority 类,这就是导致此问题的原因(没有 HttpMethod 问题)。这就是我修复它的方法

首先,删除impements并将角色变成普通的@Entity类:

@Data
@EqualsAndHashCode(of = "id")
@ToString(of = { "id" })
@Entity
public class Roles {

    private static final long serialVersionUID = -7314956574144971210L;

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

    private String name;

    @ManyToMany(mappedBy = "roles")
    private Set<Users> users;

}

然后在实现 UserDetailsService 的类中,添加以下代码:

List<GrantedAuthority> grantedAuthorities = new ArrayList<>();

users.getRoles().forEach(d -> {
    grantedAuthorities.add(new SimpleGrantedAuthority(d.getName()));
});

我无法详细解释,但我认为 List 只需要 1 个字符串,该字符串是角色名称。那么这里是完整的代码:

@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        Users users = userRepository.findByEmail(s);
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();

        users.getRoles().forEach(d -> {
            grantedAuthorities.add(new SimpleGrantedAuthority(d.getName()));
        });

        if(users == null) {
            throw new UsernameNotFoundException("Username Not Found");
        }

        return new User(users.getEmail(), users.getPassword(), grantedAuthorities);
    }
}

如果有人能找到此行的修复方法

.antMatchers(HttpMethod.GET,"/**/something").hasRole("USER")
,即我想使用 HttpMethod 来区分具有相同网址的每个方法,如果有人有答案,我会接受你的答案。等待它


0
投票

感谢您对问题的精彩表述。

这就是我的理解,您只想向具有 Admin 角色的用户授予对此 URL

/couponapi/something
的访问权限,并为所有经过身份验证的用户授予对此 URL
/couponapi/coupons/**
的访问权限,无论其角色如何 (管理员或用户)

尝试使用

hasAuthority
而不是
hasRole
并删除第一行
http.httpBasic()
,它对我有用。

所以在WebSecurityConfig.java文件中:

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/couponapi/something").hasAuthority("ROLE_ADMIN")
                .antMatchers("/**").authenticated()
                .and().httpBasic().and().csrf().disable();
    }

然后在上面的代码中,您只授予具有 ADMIN 权限的用户访问此 url

/couponapi/something
,因此具有 USER 权限的用户无法访问它。

既然您已经声明了密码编码器 bean,您可以将它与

AuthenticationManagerBuilder

一起使用
 @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

0
投票

在 Spring Security 6.x 中,我尝试将 hasRole 更改为 hasAuthority 及其工作!

© www.soinside.com 2019 - 2024. All rights reserved.