Spring Security源码分析十三:Spring Security 基于表达式的权限控制

栏目: Java · 发布时间: 8年前

内容简介:Spring Security源码分析十三:Spring Security 基于表达式的权限控制

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

前言

spring security 3.0 已经可以使用 spring el 表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。

常见的表达式

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

部分代码:

......
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 权限的用户有效。

在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 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;
    }
}

效果如下:

user-gold-cdn.xitu.io/2018/1/30/1…

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) {
      ...

   }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

Learning PHP, MySQL, and JavaScript

Learning PHP, MySQL, and JavaScript

Robin Nixon / O'Reilly Media / 2009-7-21 / USD 39.99

Learn how to create responsive, data-driven websites with PHP, MySQL, and JavaScript - whether or not you know how to program. This simple, streamlined guide explains how the powerful combination of P......一起来看看 《Learning PHP, MySQL, and JavaScript》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具