Spring Boot整合Spring Security简记-方法安全-中(九)

new無语 转载请注明原创出处,谢谢!

Spring Security学习目录

本章专讲基于表达式的访问控制。

内置表达式:


表达式 备注
hasRole([role]) 如果有当前角色,则返回true(会自动添加ROLE_前缀)
hasAnyRole([role1,role2]) 如果有任一角色即可通过校验,返回true(会自动添加ROLE_前缀)
hasAuthority([authority]) 如果有指定权限,则返回true
hasAnyAuthority([authority1,authority2]) 如果有指定任一权限,则返回true
principal 获取当前用户的主体对象
authentication 获取当前用户Authentication对象,身份验证主体
permitAll 总是返回true,表示全部允许
denyAll 总是返回false,表示全部拒绝
isAnonymous() 如果为匿名验证,则返回true
isRememberMe() 如果为Remember-Me自动认证,则返回true
isAuthenticated() 如果用户不是匿名登陆,则返回true
isFullyAuthenticated() 如果用户不是匿名登陆或Remember-Me自动认证则返回true
hasPermission(Object target, Object permission)
hasPermission(Object targetId, String targetType, Object permission)

hasIpAddress


该表达式hasIpAddress是特定于Web安全性的附加内置表达式。它是由WebSecurityExpressionRoot类定义的。
这个表达式作用为,该URL域下,受到IP访问控制。这里0:0:0:0:0:0:0:1为本机。

.antMatchers("/db/**").access("hasIpAddress('0:0:0:0:0:0:0:1')")

在WEB安全表达式中使用自定义Bean


如果你想扩展自定义表达式,在这里可以很轻易的引用你自己的Bean。例如下面WebSecurity

public class WebSecurity {
        public boolean check(Authentication authentication, HttpServletRequest request) {
                ...
        }
}

使用方法:

http
        .authorizeRequests()
                .antMatchers("/user/**").access("@webSecurity.check(authentication,request)")
                ...

安全表达式中的路径变量


考虑REST风格的URL的应用,可以提取URL中的变量信息。
例如

public class WebSecurity {
        public boolean checkUserId(Authentication authentication, int id) {
                ...
        }
}
http
        .authorizeRequests()
                .antMatchers("/user/{userId}/**").access("@webSecurity.checkUserId(authentication,#userId)")
                ...

安全表达式注释


前面也说到了,表达式的注释有四种,分别是@PreAuthorize@PreFilter@PostAuthorize@PostFilter。启动方式前面也有提过,这里就不说了。
最常用的注释就是@PreAuthorize,它来决定此次请求是否可以调用当前方法。

@PreAuthorize("hasRole('ADMIN')")
public void create(Contact contact);
@PreAuthorize("#username == principal")
@RequestMapping("test11")
public String test11(String username) {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    return "参数名与认证用户名一致。" + principal;
}

这里大家看到,第二个代码块中的方法可以使用Spring-EL(在表达式中可以使用任何Spring-EL功能)进行获取参数进行校验方法调用权限。这里是参数不为当前认证用户名的情况下,不能进行请求调用方法。

  • 处理参数还有一种方式,就是Spring Security的@P注释,如果@P注释出现在方法的单个参数上,则会使用该值。它的好处是,在使用之后,可以不包含任何参数名称的信息。
import org.springframework.security.access.method.P;

...

@PreAuthorize("#c.name == authentication.name")
public void doSomething(@P("c") Contact contact);
  • 如果Spring Data 的@Param的注解在方法参数上使用,也会使用该参数。
import org.springframework.data.repository.query.Param;

...

@PreAuthorize("#n == authentication.name")
Contact findContactByName(@Param("n") String name);

如果你有需求需要对方法进行后置校验,你就可以使用@PostAuthorize,它可以通过内置表达式returnObject进行返回值校验。

@PostAuthorize("returnObject == 'test1'")
@RequestMapping("test12")
public String test12(String param) {
    return param;
}

使用@PreFilter@PostFilter进行过滤

Spring Security还支持对集合和数组的过滤。
当使用@PostFilter注释时,Spring Security会遍历返回的集合并删除提供的表达式为false的所有元素。
filterObject指的是返回集合中的当前对象。

@PostFilter("filterObject.username == 'testuser2'")
@RequestMapping("getAll")
public List getAll() {
    UserDetails details = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getDetails();
    List list = new ArrayList<>();
    list.add(details);
    return list;
}

您也可以在方法调用之前进行筛选@PreFilter,尽管这是一个不太常见的要求。语法是一样的,但如果有多个参数是一个集合类型,那么你必须使用filterTarget这个注释的属性来选择一个名称。

请注意,过滤显然不能替代您的数据检索查询。如果你正在过滤大集合并删除很多条目,那么这可能是低效的。

你可能感兴趣的:(Spring Boot整合Spring Security简记-方法安全-中(九))