springSecurity基於表達式鑑權

前言

上一篇文章已經介紹了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開發小驛站

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章