有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在Spring安全性中正确使用hasRole?

嗨,我试图实现的是保护一个url,只有一个角色可以访问它,当我尝试添加。hasRole(“用户”),其他角色仍然可以访问它。我是这样做的:

这是我的控制器:

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

}

我只想为角色_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;
    }
}

下面是我实现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());
    }
}

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

enter image description here

如您所见,我有角色用户和角色管理员

这是我的数据库

enter image description here

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


共 (3) 个答案

  1. # 1 楼答案

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

    @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();
    }
    
  2. # 2 楼答案

    谢谢你对你的问题做了很好的介绍

    这就是我所说的,您只想让具有管理员角色的用户访问此URL/couponapi/something,并让所有经过身份验证的用户访问此URL/couponapi/coupons/**,无论其角色是(管理员还是用户)

    尝试使用hasAuthority而不是hasRole并删除第一行http.httpBasic(),这对我很有效

    所以在WebSecurity配置中。java文件:

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

    然后在上面的代码部分中,您只向具有管理权限的用户授予访问此url的权限/couponapi/something,因此具有用户权限的用户无法访问它

    由于您已经声明了密码编码器bean,所以可以将其与AuthenticationManagerBuilder一起使用

     @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        }
    
  3. # 3 楼答案

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

    首先,删除提示并将角色转换为常用的@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()));
    });
    

    我无法详细解释,但我认为列表只需要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的每个方法,如果有人有答案,我将接受您的答案。等待