Spring Security(14)——权限鉴定基础

简介: 权限鉴定基础   目录 1.1     Spring Security的AOP Advice思想 1.2     AbstractSecurityInterceptor 1.2.1    ConfigAttribute 1.2.2    RunAsManager 1.2.3    AfterInvocationManager          Spring Security的权限鉴定是由AccessDecisionManager接口负责的。

权限鉴定基础

 

目录

1.1     Spring SecurityAOP Advice思想

1.2     AbstractSecurityInterceptor

1.2.1    ConfigAttribute

1.2.2    RunAsManager

1.2.3    AfterInvocationManager

 

       Spring Security的权限鉴定是由AccessDecisionManager接口负责的。具体来说是由其中的decide()方法负责,其定义如下。

    void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)

        throws AccessDeniedException, InsufficientAuthenticationException;

 

       如你所见,该方法接收三个参数,第一个参数是包含当前用户信息的Authentication对象;第二个参数表示当前正在请求的受保护的对象,基本上来说是MethodInvocation(使用AOP)、JoinPoint(使用Aspectj)和FilterInvocationWeb请求)三种类型;第三个参数表示与当前正在访问的受保护对象的配置属性,如一个角色列表。

 

1.1     Spring SecurityAOP Advice思想

       对于使用AOP而言,我们可以使用几种不同类型的advicebeforeafterthrowsaround。其中around advice是非常实用的,通过它我们可以控制是否要执行方法、是否要修改方法的返回值,以及是否要抛出异常。Spring Security在对方法调用和Web请求时也是使用的around advice的思想。在方法调用时,可以使用标准的Spring AOP来达到around advice的效果,而在进行Web请求时是通过标准的Filter来达到around advice的效果。

       对于大部分人而言都比较喜欢对Service层的方法调用进行权限控制,因为我们的主要业务逻辑都是在Service层进行实现的。如果你只是想保护Service层的方法,那么使用Spring AOP就可以了。如果你需要直接保护领域对象,那么你可以考虑使用Aspectj

       你可以选择使用AspectjSpring AOP对方法调用进行鉴权,或者选择使用FilterWeb请求进行鉴权。当然,你也可以选择使用这三种方式的任意组合进行鉴权。通常的做法是使用FilterWeb请求进行一个比较粗略的鉴权,辅以使用Spring AOPService层的方法进行较细粒度的鉴权。

 

1.2     AbstractSecurityInterceptor

       AbstractSecurityInterceptor是一个实现了对受保护对象的访问进行拦截的抽象类,其中有几个比较重要的方法。beforeInvocation()方法实现了对访问受保护对象的权限校验,内部用到了AccessDecisionManagerAuthenticationManagerfinallyInvocation()方法用于实现受保护对象请求完毕后的一些清理工作,主要是如果在beforeInvocation()中改变了SecurityContext,则在finallyInvocation()中需要将其恢复为原来的SecurityContext,该方法的调用应当包含在子类请求受保护资源时的finally语句块中;afterInvocation()方法实现了对返回结果的处理,在注入了AfterInvocationManager的情况下默认会调用其decide()方法。AbstractSecurityInterceptor只是提供了这几种方法,并且包含了默认实现,具体怎么调用将由子类负责。每一种受保护对象都拥有继承自AbstractSecurityInterceptor的拦截器类, MethodSecurityInterceptor将用于调用受保护的方法,而FilterSecurityInterceptor将用于受保护的Web请求。它们在处理受保护对象的请求时都具有一致的逻辑,具体的逻辑如下。

       1、先将正在请求调用的受保护对象传递给beforeInvocation()方法进行权限鉴定。

       2、权限鉴定失败就直接抛出异常了。

       3、鉴定成功将尝试调用受保护对象,调用完成后,不管是成功调用,还是抛出异常,都将执行finallyInvocation()

       4、如果在调用受保护对象后没有抛出异常,则调用afterInvocation()

 

       以下是MethodSecurityInterceptor在进行方法调用的一段核心代码。

    public Object invoke(MethodInvocation mi) throws Throwable {

        InterceptorStatusToken token = super.beforeInvocation(mi);

 

        Object result;

        try {

            result = mi.proceed();

        } finally {

            super.finallyInvocation(token);

        }

        returnsuper.afterInvocation(token, result);

    }

 

1.2.1   ConfigAttribute

       AbstractSecurityInterceptorbeforeInvocation()方法内部在进行鉴权的时候使用的是注入的AccessDecisionManagerdecide()方法进行的。如前所述,decide()方法是需要接收一个受保护对象对应的ConfigAttribute集合的。一个ConfigAttribute可能只是一个简单的角色名称,具体将视AccessDecisionManager的实现者而定。AbstractSecurityInterceptor将使用一个SecurityMetadataSource对象来获取与受保护对象关联的ConfigAttribute集合,具体SecurityMetadataSource将由子类实现提供。ConfigAttribute将通过注解的形式定义在受保护的方法上,或者通过access属性定义在受保护的URL上。例如我们常见的<intercept-url pattern=”/**” access=”ROLE_USER,ROLE_ADMIN”/>就表示将ConfigAttribute ROLE_USERROLE_ADMIN应用在所有的URL请求上。对于默认的AccessDecisionManager的实现,上述配置意味着用户所拥有的权限中只要拥有一个GrantedAuthority与这两个ConfigAttribute中的一个进行匹配则允许进行访问。当然,严格的来说ConfigAttribute只是一个简单的配置属性而已,具体的解释将由AccessDecisionManager来决定。

 

1.2.2  RunAsManager

       在某些情况下你可能会想替换保存在SecurityContext中的Authentication。这可以通过RunAsManager来实现的。在AbstractSecurityInterceptorbeforeInvocation()方法体中,在AccessDecisionManager鉴权成功后,将通过RunAsManager在现有Authentication基础上构建一个新的Authentication,如果新的Authentication不为空则将产生一个新的SecurityContext,并把新产生的Authentication存放在其中。这样在请求受保护资源时从SecurityContext中获取到的Authentication就是新产生的Authentication。待请求完成后会在finallyInvocation()中将原来的SecurityContext重新设置给SecurityContextHolderAbstractSecurityInterceptor默认持有的是一个对RunAsManager进行空实现的NullRunAsManager。此外,Spring SecurityRunAsManager有一个还有一个非空实现类RunAsManagerImpl,其在构造新的Authentication时是这样的逻辑:如果受保护对象对应的ConfigAttribute中拥有以“RUN_AS_”开头的配置属性,则在该属性前加上“ROLE_”,然后再把它作为一个GrantedAuthority赋给将要创建的Authentication(如ConfigAttribute中拥有一个“RUN_AS_ADMIN”的属性,则将构建一个“ROLE_RUN_AS_ADMIN”的GrantedAuthority),最后再利用原Authenticationprincipal、权限等信息构建一个新的Authentication进行返回;如果不存在任何以“RUN_AS_”开头的ConfigAttribute,则直接返回nullRunAsManagerImpl构建新的Authentication的核心代码如下所示。

    public Authentication buildRunAs(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {

        List<GrantedAuthority> newAuthorities = new ArrayList<GrantedAuthority>();

        for (ConfigAttribute attribute : attributes) {

            if (this.supports(attribute)) {

                GrantedAuthority extraAuthority = new SimpleGrantedAuthority(getRolePrefix() + attribute.getAttribute());

                newAuthorities.add(extraAuthority);

            }

        }

        if (newAuthorities.size() == 0) {

            returnnull;

        }

        // Add existing authorities

        newAuthorities.addAll(authentication.getAuthorities());

        returnnew RunAsUserToken(this.key, authentication.getPrincipal(), authentication.getCredentials(),

                newAuthorities, authentication.getClass());

    }

 

1.2.3  AfterInvocationManager

       在请求受保护的对象完成以后,可以通过afterInvocation()方法对返回值进行修改。AbstractSecurityInterceptor把对返回值进行修改的控制权交给其所持有的AfterInvocationManager了。AfterInvocationManager可以选择对返回值进行修改、不修改或抛出异常(如:后置权限鉴定不通过)。

 

       以下是Spring Security官方文档提供的一张关于AbstractSecurityInterceptor相关关系的图。



 

 

(注:本文是基于Spring Security3.1.6所写)

(注:原创文章,转载请注明出处。原文地址:http://elim.iteye.com/blog/2211966

 

 

 

目录
相关文章
|
29天前
|
JSON 安全 Java
什么是JWT?如何使用Spring Boot Security实现它?
什么是JWT?如何使用Spring Boot Security实现它?
123 5
|
5月前
|
安全 Java 数据安全/隐私保护
使用Spring Security实现细粒度的权限控制
使用Spring Security实现细粒度的权限控制
|
5月前
|
安全 Java 数据库
实现基于Spring Security的权限管理系统
实现基于Spring Security的权限管理系统
|
5月前
|
安全 Java 数据安全/隐私保护
解析Spring Security中的权限控制策略
解析Spring Security中的权限控制策略
|
5月前
|
安全 Java 数据安全/隐私保护
使用Spring Security实现细粒度的权限控制
使用Spring Security实现细粒度的权限控制
|
5月前
|
安全 Java 数据安全/隐私保护
使用Java和Spring Security实现身份验证与授权
使用Java和Spring Security实现身份验证与授权
|
前端开发 Java 数据库连接
|
2月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
247 2
|
6天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
13天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
58 14