Spring Security 基於表達式的權限控制

前言

spring security 3.0已經能夠使用spring el表達式來控制受權,容許在表達式中使用複雜的布爾邏輯來控制訪問的權限。java

常見的表達式

Spring Security可用表達式對象的基類是SecurityExpressionRoot。git

表達式 描述
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

部分代碼:github

......
private String defaultRolePrefix = "ROLE_"; //ROLE_前綴

	/** Allows "permitAll" expression */
	public final boolean permitAll = true; //所有true

	/** Allows "denyAll" expression */
	public final boolean denyAll = false; //所有false
public final boolean permitAll() {
		return true;
	}

	public final boolean denyAll() {
		return false;
	}

	public final boolean isAnonymous() {
		//是不是anonymous
		return trustResolver.isAnonymous(authentication);
	}

	public final boolean isRememberMe() {
		//是不是rememberme
		return trustResolver.isRememberMe(authentication);
	}
......

URL安全表達式

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

這裏咱們定義了應用/person/*URL的範圍,該URL只針對擁有ADMIN或者USER權限的用戶有效。spring

在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)");

RbacServiceImplexpress

@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 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提供了四種註解,分別是@PreAuthorize , @PreFilter , @PostAuthorize 和 @PostFilterapp

使用method註解

  1. 開啓方法級別註解的配置
    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class MerryyouSecurityConfig extends WebSecurityConfigurerAdapter {
  2. 配置相應的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();
     }
  3. 在方法上面使用註解
    /**
    * 查詢全部人員 
    */ 
    @PreAuthorize(「hasRole(‘ADMIN’)」) 
    @ApiOperation(value = 「得到person列表」, notes = 「」) 
    @GetMapping(value = 「/persons」) 
    public List getPersons() { 
        return personService.findAll(); 
    }

PreAuthorizeide

@PreAuthorize 註解適合進入方法前的權限驗證工具

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

PostAuthorizeui

@PostAuthorize 在方法執行後再進行權限驗證,適合驗證帶有返回值的權限。Spring EL 提供 返回對象可以在表達式語言中獲取返回的對象return Object

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

PreFilter 針對參數進行過濾

//當有多個對象是使用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();

效果以下:

相關文章
相關標籤/搜索