Spring Security 基于(url /method)表达式权限控制

 

常见的表达式

      Spring Security可用表达式对象的基类是SecurityExpressionRoot

表达式描述
hasRole([role])用户拥有制定的角色时返回true (Spring security 默认会带有ROLE_前缀),去除参考Remove the ROLE_
hasAnyRole([role1,role2])用户拥有任意一个制定的角色时返回true
hasAuthority([authority])等同于hasRole,但不会带有ROLE_前缀
hasAnyAuthority([auth1,auth2])等同于hasAnyRole
permitAll永远返回true
denyAll永远返回false
anonymous当前用户是anonymous时返回true
rememberMe当前勇士是rememberMe用户返回true
authentication当前登录用户的authentication对象
fullAuthenticated当前用户既不是anonymous也不是rememberMe用户时返回true
hasIpAddress('192.168.1.0/24'))请求发送的IP匹配时返回true

URL安全表达式

onfig.antMatchers("/person/*").access("hasRole('ADMIN') or hasRole('USER')")
                .anyRequest().authenticated();

这里我们定义了应用/person/*URL的范围,该URL只针对拥有ADMIN或者USER权限的用户有效。

在Web安全表达式中引用bean

config.antMatchers("/person/*").access("hasRole('ADMIN') or hasRole('USER')")
                .antMatchers("/person/{id}").access("@rbacService.checkUserId(authentication,#id)")
                .anyRequest()
                .access("@rbacService.hasPermission(request,authentication)");

RbacServiceImpl

@Component("rbacService")
@Slf4j
public class RbacServiceImpl implements RbacService {
    /**
     * uri匹配工具
     */
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        log.info("【RbacServiceImpl】  --hasPermission={}", authentication.getPrincipal());
        Object principal = authentication.getPrincipal();

        boolean hasPermission = false;
        //有可能是匿名的anonymous
        if (principal instanceof org.springframework.security.core.userdetails.UserDetails) {
            //admin永远放回true
            if (StringUtils.equals("admin", ((SysUser) principal).getUsername())) {
                hasPermission = true;
            } else {
                //读取用户所拥有权限所有的URL 在这里全部返回true
                Set<String> urls = new HashSet<>();

                for (String url : urls) {
                    if (antPathMatcher.match(url, request.getRequestURI())) {
                        hasPermission = true;
                        break;
                    }
                }
            }
        }
        return hasPermission;
    }

	  public boolean checkUserId(Authentication authentication, int id) {
        return true;
    }
}

 

Method安全表达式

针对方法级别的访问控制比较复杂,Spring Security提供了四种注解,分别是@PreAuthorize , @PreFilter , @PostAuthorize , @PostFilter

使用method注解

  1. 开启方法级别注解的配置
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MerryyouSecurityConfig extends WebSecurityConfigurerAdapter {
  1. 配置相应的bean
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

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

    @Bean
    @ConditionalOnMissingBean(PasswordEncoder.class)
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
  1. 在方法上面使用注解
 /**
  * 查询所有人员
  */
 @PreAuthorize("hasRole('ADMIN')")
 @ApiOperation(value = "获得person列表", notes = "")
 @GetMapping(value = "/persons")
 public List<Person> getPersons() {
    return personService.findAll();
 }

PreAuthorize

@PreAuthorize 注解适合进入方法前的权限验证

@PreAuthorize("hasRole('ADMIN')")
List<Person> findAll();

PostAuthorize

@PostAuthorize 在方法执行后再进行权限验证,适合验证带有返回值的权限。Spring EL 提供 返回对象能够在表达式语言中获取返回的对象returnObject

@PostAuthorize("returnObject.name == authentication.name")
Person findOne(Integer id);

PreAuthorize 针对参数进行过滤

//当有多个对象是使用filterTarget进行标注
@PreFilter(filterTarget="ids", value="filterObject%2==0")
public void delete(List<Integer> ids, List<String> usernames) {
   ...
}

PostFilter 针对返回结果进行过滤

 @PreAuthorize("hasRole('ADMIN')")
 @PostFilter("filterObject.name == authentication.name")
 List<Person> findAll();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值