766°

springSecurity基于表达式鉴权

@[TOC]

前言

上一篇文章已经介绍了springSecurity的使用了,本篇文章主要介绍一下使用spring EL表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限

常见的表达式

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

表达式 描述
hasRole([role]) 用户拥有指定的角色时返回true(hasRole()默认会将配置中的 role 带有 ROLE_ 前缀再和用户的角色权限 进行对比)
hasAnyRole([role1,role2]) 用户拥有任意一个指定中的角色时返回true
hasAuthority([auth]) 同hasRole()但不添加前缀 ROLE_
hasAnyAuthority([auth1,auth2]) 同hasAnyRole([auth1,auth2]),但不添加前缀 ROLE_
permitAll 永远返回true
denyAll 永远返回false
anonymous 当前用户时 anonymous(匿名、未认证)时返回true
rememberMe 当前用户时 rememberMe(记住登录) 时发挥true
authentication 当前登录用户的 authentication 对象
fullAuthticated 当前用户既不是 anonymous 也不是 rememberMe 时返回true(即正常认证登录时返回true)
hasIpAddress("192.168.1.0/24") ip匹配时返回true

如果需要移除hasRole的前缀,在security配置类中添加如下代码

	@Bean
    GrantedAuthorityDefaults grantedAuthorityDefaults(){
        return new GrantedAuthorityDefaults("");//remove the ROLE_ prefix
    }

URL安全表达式

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

这里我们定义了 /test/ URL的范围,只有拥有 ADMINUSER 权限的用户可以访问 /test/ 匹配的URL

在Web 安全表达式中引用Bean自定义鉴权

http.antMatchers("/test/*").access("hasRole('ADMIN') or hasRole('USER')")
                .antMatchers("/test/{id}").access("@rbacauthorityservice.checkTestId(authentication,#id)")//可以传递参数
                .anyRequest()
                .access("@rbacauthorityservice.hasPermission(request,authentication)");

rbacauthorityservice

@Component("rbacauthorityservice")
@Slf4j
public class Rbacauthorityservice {
    /**
     * uri匹配工具
     */
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        log.info("【Rbacauthorityservice】  --hasPermission={}", authentication.getPrincipal());
        Object principal = authentication.getPrincipal();
        //根据自己的业务来
        boolean hasPermission = false;
        //有可能是匿名的anonymous
        if (principal instanceof SysUser) {
            //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提供了4种注解分别是 @PreAuthorize ,@PreFilter,@PostAuthorize,@PostFilter

使用method注解

开启方法级别的注解配置

在security配置类中添加注解

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConf extends WebSecurityConfigurerAdapter {

其他配置忽略。。。可查看上一篇文章

在方法上使用注解

	/**
     * 查询所有人员
     */
    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping(value = "/users")
    public List<User> getUsers() {
        return userService.findAll();
    }
PreAuthorize

@ProAuthorize 注解适合进入方法钱的权限验证

	@PreAuthorize("hasRole('ADMIN')")
	list<User> findAll();
PostAuthorize

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

	@PostAUthorize("returnObject.username == authentication.username")
	User findOne(long id);
PreAuthorize针对参数进行过滤
	//当有多个对象时使用filterTarget进行标柱
	@PreFilter(filterTarget = "ids",value = "filterObject % 2 == 0")
	void delete(List<Long> ids);

PostFilter 针对返回结果进行过滤

	@PreAuthorize("hasAuthority('user:list')")
	@PostFilter("filterObject.username == authentication.username")
	List<User> findAll();

源码

github地址:https://github.com/jamesluozhiwei/security

如果对您有帮助请高抬贵手点个star


个人博客:https://www.cqwxhn.xin

关注公众号获取更多咨询

Java开发小驿站


全部评论: 0

    我有话说: