【问题标题】:How to use hasRole in Spring Security properly?如何正确使用 Spring Security 中的 hasRole?
【发布时间】:2021-04-07 20:19:16
【问题描述】:

嗨,我试图实现的是保护一个只有一个角色可以访问它的 url,当我尝试添加 .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");
    }

}

我只想为 ROLE_ADMIN 保护@GetMapping("/something"),这是我的 Spring 安全配置的样子:

@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;
    }
}

这是我实现 UserDetailsS​​ervice 类的服务:

@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

这是我加入的数据库

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

【问题讨论】:

  • 你可以尝试将hasRole 更改为hasAuthority,没有任何意义,但如果你可以尝试
  • 当然,我试试这个 .hasAuthority("ROLE_USER") 还是一样的结果,不工作
  • 好的,请在CouponController 中添加一个参数Authentication 并检查其中的所有字段是什么
  • 你的意思是这样吗? @GetMapping("/something") public Coupon findByCodeX(Authentication auth) { return couponRepository.findByCode("SUPERSALE"); } 我如何检查其中的所有字段人口?
  • 请这样

标签: java spring spring-boot spring-security spring-data


【解决方案1】:

感谢您对问题的良好介绍。

这就是我所理解的,您只想向具有 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());
    }

【讨论】:

    【解决方案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();
    }
    

    【讨论】:

    • 嗨,是的,我想出了一个,但我仍然有关于 HttpMethod.GET 等的问题,我仍然无法让它工作
    【解决方案3】:

    我在这里找到了罪魁祸首,但不完全是我仍然缺少 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;
    
    }
    

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

    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 来区分具有相同 url 的每个方法,如果有人有答案,我会接受你的答案。等着呢

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-07
      • 2022-01-01
      • 2011-03-02
      • 2015-08-27
      • 2015-05-02
      • 2017-06-16
      相关资源
      最近更新 更多