Spring Security 授权体系结构

这篇具有很好参考价值的文章主要介绍了Spring Security 授权体系结构。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1、Authorities 授权(AuthorizationFilter 过滤器)

2、AuthorizationManager 授权管理器

3、角色的层次化(Roles)


1、Authorities 授权(AuthorizationFilter 过滤器)

        通过 Authentication.getAuthorities() 可获取已通过验证的用户授权信息(GrantedAuthority),GrantedAuthority 对象由 AuthenticationManager 插入到 Authentication 对象中,然后在做出授权决策时由 AuthorizationManager 实例读取

        AuthenticationManager 的常用实现为 ProviderManager,ProviderManager.authenticate 在进行身份验证完成后,会填充 Authentication 对象,其中就包括对象的授权信息(GrantedAuthority)。

//具体授权的Provider列表
private List<AuthenticationProvider> providers;

//授权方法
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        //省略...

        //1-定义身份验证对象
        Authentication result = null;
        Authentication parentResult = null;
        int currentPosition = 0;
        int size = this.providers.size();
        Iterator var9 = this.getProviders().iterator();

        while(var9.hasNext()) {
            AuthenticationProvider provider = (AuthenticationProvider)var9.next();
            if (provider.supports(toTest)) {
                //省略...

                try {

                    //2-通过用户验证后,在这里返回填充好的Authentication对象
                    result = provider.authenticate(authentication);

                    if (result != null) {
                        this.copyDetails(authentication, result);
                        break;
                    }
                } catch (InternalAuthenticationServiceException | AccountStatusException var14) {
                    this.prepareException(var14, authentication);
                    throw var14;
                } catch (AuthenticationException var15) {
                    lastException = var15;
                }
            }
        }

        //省略...

        if (result != null) {
            if (this.eraseCredentialsAfterAuthentication && result instanceof CredentialsContainer) {
                ((CredentialsContainer)result).eraseCredentials();
            }

            if (parentResult == null) {
                this.eventPublisher.publishAuthenticationSuccess(result);
            }
            //3-在这里将封装的对象返回
            return result;
        } else {
            if (lastException == null) {
                lastException = new ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound", new Object[]{toTest.getName()}, "No AuthenticationProvider found for {0}"));
            }

            if (parentException == null) {
                this.prepareException((AuthenticationException)lastException, authentication);
            }
            throw lastException;
        }
    }

        ​​​AuthenticationProvider 的实现有很多,这里使用常用的 AbstractUserDetailsAuthenticationProvider 来看一下用户权限的填充步骤。

    //AbstractUserDetailsAuthenticationProvider.authenticate方法
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        //省略...

        //1-获取用户名称
        String username = this.determineUsername(authentication);

        //2-从缓存中获取用户信息(UserDetails)
        boolean cacheWasUsed = true;
        UserDetails user = this.userCache.getUserFromCache(username);
        if (user == null) {
            cacheWasUsed = false;

            try {
                //3-缓存中无用户信息,再去查找其他UserDetails的实现
                user = this.retrieveUser(username, (UsernamePasswordAuthenticationToken)authentication);
            } catch (UsernameNotFoundException var6) {
                //错误处理,省略...
        }

        //省略..

        //4-最后这个返回,就是返回封装好的Authentication对象
        return this.createSuccessAuthentication(principalToReturn, authentication, user);
    }

    //封装Authentication对象
    protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) {

        //在这里设置了用户的权限->user.getAuthorities() -> GrantedAuthority
        UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, authentication.getCredentials(), this.authoritiesMapper.mapAuthorities(user.getAuthorities()));

        result.setDetails(authentication.getDetails());
        this.logger.debug("Authenticated user");
        return result;
    }

        用户权限填充完了,什么时候取用呢?权限信息由授权过滤器 AuthorizationFilter 在进行授权的时候取用。

//授权过滤器
public class AuthorizationFilter extends OncePerRequestFilter {

    //授权管理器
    private final AuthorizationManager<HttpServletRequest> authorizationManager;

    public AuthorizationFilter(AuthorizationManager<HttpServletRequest> authorizationManager) {
        Assert.notNull(authorizationManager, "authorizationManager cannot be null");
        this.authorizationManager = authorizationManager;
    }

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        // verify方法进行授权验证,this::getAuthentication 获取权限信息
        this.authorizationManager.verify(this::getAuthentication, request);

        filterChain.doFilter(request, response);
    }

    private Authentication getAuthentication() {
        //从SecurityContextHolder中获取权限信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication == null) {
            throw new AuthenticationCredentialsNotFoundException("An Authentication object was not found in the SecurityContext");
        } else {
            return authentication;
        }
    }
}

2、AuthorizationManager 授权管理器

        AuthorizationManager,用来确定 Authentication 是否有权访问特定对象。

        在 Spring Security 中 AuthorizationManager 取代了 AccessDecisionManager AccessDecisionVoter

        Spring 官方鼓励自定义 AccessDecisionManager 或 AccessDecisionVoter 的应用程序改为使用 AuthorizationManager

        AuthorizationManager 由 AuthorizationFilter 调用,负责做出最终的访问控制决策。AuthorizationManager 接口包含两个方法://函数式接口

@FunctionalInterface
public interface AuthorizationManager<T> {

    //确定是否为特定Authentication或对象授予访问权限。
    default void verify(Supplier<Authentication> authentication, T object) {
        AuthorizationDecision decision = this.check(authentication, object);
        if (decision != null && !decision.isGranted()) {
            throw new AccessDeniedException("Access Denied");
        }
    }

    //确定是否为特定Authentication或对象授予访问权限。
    @Nullable
    AuthorizationDecision check(Supplier<Authentication> var1, T var2);
}

        用户可以通过实现 AuthorizationManager 接口来自定义授权控制,同时,Spring Security 附带了一个委托 AuthorizationManager,它可以与各个 AuthorizationManager 进行协作。

        RequestMatcherDelegatingAuthorizationManager 将选择最合适的 AuthorizationManager 匹配请求。对于方法的安全控制,可以使用 AuthorizationManagerBeforeMethodInterceptor AuthorizationManagerAfterMethodInterceptor 进行实现。//注意,这两个拦截器在5.6后的版本中才有

    //请求匹配器和授权管理器的集合
    private final Map<RequestMatcher, AuthorizationManager<RequestAuthorizationContext>> mappings;  
  
    //RequestMatcherDelegatingAuthorizationManager.check方法
    public AuthorizationDecision check(Supplier<Authentication> authentication, HttpServletRequest request) {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace(LogMessage.format("Authorizing %s", request));
        }
        //1-获取请求匹配器和授权管理器集合的迭代器
        Iterator var3 = this.mappings.entrySet().iterator();

        Entry mapping;
        MatchResult matchResult;
        do {
            if (!var3.hasNext()) {
                this.logger.trace("Abstaining since did not find matching RequestMatcher");
                return null;
            }
            //2-获取一个Entry
            mapping = (Entry)var3.next();
            //3-获取一个RequestMatcher 
            RequestMatcher matcher = (RequestMatcher)mapping.getKey();
            //4-进行匹配
            matchResult = matcher.matcher(request);
        } while(!matchResult.isMatch());

        //5-如果匹配成功,会选择一个对应的授权器:AuthorizationManager
        AuthorizationManager<RequestAuthorizationContext> manager = (AuthorizationManager)mapping.getValue();
        if (this.logger.isTraceEnabled()) {
            this.logger.trace(LogMessage.format("Checking authorization on %s using %s", request, manager));
        }

        //6-选择特定的授权管理器进行授权操作
        return manager.check(authentication, new RequestAuthorizationContext(request, matchResult.getVariables()));
    }

        AuthorizationManagerBeforeMethodInterceptor: 是一个方法拦截器,它使用 AuthorizationManager 来确定一个 Authentication 是否可以调用给定的 MethodInvocation。//该拦截器在方法调用前进行拦截

    //授权管理器
    private final AuthorizationManager<MethodInvocation> authorizationManager;    
    
    //AuthorizationManagerBeforeMethodInterceptor.attemptAuthorization方法
    //在该拦截器中尝试使用授权管理器进行授权
    private void attemptAuthorization(MethodInvocation mi) {
        this.logger.debug(LogMessage.of(() -> {
            return "Authorizing method invocation " + mi;
        }));
        //1-执行授权操作
        AuthorizationDecision decision = this.authorizationManager.check(this.authentication, mi);

        //2-发布授权事件(Authentication对象,调用方法,授权结果)
        this.eventPublisher.publishAuthorizationEvent(this.authentication, mi, decision);

        if (decision != null && !decision.isGranted()) {

            //3-授权失败,记录日志,抛出异常
            this.logger.debug(LogMessage.of(() -> {
                return "Failed to authorize " + mi + " with authorization manager " + this.authorizationManager + " and decision " + decision;
            }));
            throw new AccessDeniedException("Access Denied");
        } else {

             //4-授权成功,记录日志,后续执行指定方法
            this.logger.debug(LogMessage.of(() -> {
                return "Authorized method invocation " + mi;
            }));
        }
    }

    //AuthorizationManagerBeforeMethodInterceptor.invoke方法
    public Object invoke(MethodInvocation mi) throws Throwable {
        //1-调用拦截器进行授权
        this.attemptAuthorization(mi);

        //2-授权成功后执行指定方法(此时授权没有抛出异常)
        return mi.proceed();
    }

        对应的授权管理器,Spring Security 提供了指定的授权器 PreAuthorizeAuthorizationManager,在该授权器中执行授权相关操作。

        AuthorizationManagerAfterMethodInterceptor:也是一个MethodInterceptor,它可以使用 AuthorizationManager 来确定一个 Authentication 是否可以访问一个 MethodInvocation 的结果。//这个拦截器是在方法调用结束后进行拦截

        授权管理器(AuthorizationManager)的实现类图示:

Spring Security 授权体系结构,Spring Security,Spring Security

3、角色的层次化(Roles)

        应用程序中的尝尝指定一个特定的角色会自动“包含”其他的角色。例如,在具有“Admin”和“User”角色概念的应用程序中,希望管理员(“Admin”)能够执行普通用户(“User”)的所有操作。要实现这一需求,就要确保所有管理员角色也被分配了“User”角色。

        角色层次结构允许配置一个角色(或权限)时可以包含其他角色。Spring Security 的 RoleVoter 的扩展版本 RoleHierarchyVoter 配置了一个 RoleHierarchy,它从中获得分配给用户的所有“可访问权限”。//角色选择器

        典型的配置可能是这样的:

@Bean
AccessDecisionVoter hierarchyVoter() {
    RoleHierarchy hierarchy = new RoleHierarchyImpl();
    hierarchy.setHierarchy("ROLE_ADMIN > ROLE_STAFF\n" +
            "ROLE_STAFF > ROLE_USER\n" +
            "ROLE_USER > ROLE_GUEST");
    return new RoleHierarchyVoter(hierarchy);
}

        在上边代码中定义了四个层次结构的角色:

ROLE_ADMIN ⇒ ROLE_STAFF ⇒ ROLE_USER ⇒ ROLE_GUEST

        使用 ROLE_ADMIN 角色进行身份验证的用户,会同时拥有其他角色的权限,其中 ">" 可以被看成”包括“的意思。

        注意:RoleHierarchy bean 配置还没有移植到 @EnableMethodSecurity。因此,本例使用的是 AccessDecisionVoter。如果需要 RoleHierarchy 来支持方法的安全性,请继续使用@EnableGlobalMethodSecurity,直到这个bug修复完成。//这个配置是有bug的,后续应该可以正常使用

        顺便提一下,Spring Security 也提供了 AccessDecisionManager 和 AccessDecisionVoters 适配 AuthorizationManager 的方式,用来兼容之前的代码,请点击这里。

        至此,Spring Security 的授权架构介绍完毕,在这篇文章中,更多的是方法论,具体的使用细节将在后续文章中进行补充。文章来源地址https://www.toymoban.com/news/detail-607049.html

到了这里,关于Spring Security 授权体系结构的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OSI体系结构和TCP/IP体系结构

     在第一章( 计网第一章 )的时候,曾经提到过OSI体系结构和TCP/IP体系结构,并对它们进行了简单的对比。这篇博客在其基础上进行更深层次的理解。 计算机网络在逻辑功能上可以分为通信子网和资源子网两部分。 事实上,OSI将低三层称为通信子网,即为了联网而附加的通

    2024年02月07日
    浏览(37)
  • 【体系结构】山东大学计算机体系结构知识点清单

    涵盖所有考点,复习绝对高效,点赞+留邮箱获取pdf版本 1. 计算机系统的层次结构 语言实现的两种基本技术: 翻译:先把 N+1 级程序全部转换成 N 级程序后,再去执行新产生的 N 级程序,在执行过程中 N+1 级程序不再被访问。 解释:每当一条 N+1 级指令被译码后,就直接去执

    2024年02月11日
    浏览(48)
  • 计算机网络七层体系结构(OSI七层结构)、TCP/IP四层模型、网络五层体系结构

    计算机网络七层体系结构(OSI七层结构)、TCP/IP四层模型、网络五层体系结构 七层体系结构(OSI七层结构) :为了使全世界不同体系结构的计算机能够互联,国际化标准组织ISO提出开放系统互联基本参考模型,简称OSI,即所谓的7层协议体系结构。 TCP/IP四层模型 :是由实际

    2024年02月06日
    浏览(42)
  • 计算机网络——计算机网络体系结构(2/4)-分层的必要性(五层协议原理体系结构)

    目录 物理层 数据链路层 网络层 运输层 应用层 计算机网络是个非常复杂的系统。 早在最初的ARPANET设计时就提出了分层的设计理念。 \\\"分层\\\"可将庞大而复杂的问题,转化为若干较小的局部问题,而这些较小的局部问题就比较易于研究和处理。 下面,我们以五层原理结构体系

    2024年02月07日
    浏览(38)
  • MySQL体系结构

     🎉欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克🍹 ✨博客主页:小小恶斯法克的博客 🎈该系列文章专栏:重拾MySQL-进阶篇 🍹文章作者技术和水平很有限,如果文中出现错误,希望大家能指正🙏 📜 感谢大家的关注! ❤️ 目录 🚀 MySQL体系

    2024年01月22日
    浏览(68)
  • 计算机体系结构

    目录 第一章 基本概念 1.虚拟计算机 2.计算机系统结构的定义 3.佛林(Flynn)分类法 4.Amdahl定律 5.CPU性能公式 6.程序访问的局部性原理 第二章 指令系统 1.数据表示与数据类型 2.浮点数的表示方式 3.编址方式 4.寻址方式 5.指令系统的优化设计  6.Huffman编码法 7.拓展编码 8.两种方

    2024年02月06日
    浏览(44)
  • 集合体系结构

    List系列集合:添加的元素有序,可重复,有索引 Collection:是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的 set系列集合:添加的元素无序,不重复,无索引   方法名 说明 public boolean add(E e) 把给定的对象添加到当前集合中 public void clear() 清空集合中所有的

    2024年02月09日
    浏览(36)
  • 冯诺依曼体系结构

    冯·诺依曼体系结构(von Neumann architecture)是现代计算机体系结构的基础,也是目前广泛应用的计算机体系结构之一。它是由物理学家、数学家冯·诺依曼在1945年提出的,被认为是现代计算机的奠基之作。冯·诺依曼体系结构具有存储程序和通用性的特点,这意味着计算机的指

    2023年04月23日
    浏览(30)
  • 了解 PostgreSQL 体系结构

    PostgreSQL 是客户端/服务器关系数据库管理系统 (RDMS)。 PostgreSQL 还支持各种扩展插件,例如 Azure Database for PostgreSQL 超大规模 Citus 选项中的 Citus 扩展插件。 将扩展插件加载到数据库中后,它将像任何内置功能一样正常运行。 PostgreSQL 也有自己的查询语言,称为 pgsql。 此外,

    2024年02月16日
    浏览(31)
  • JVM 体系结构

    JVM: 跨平台语言 需要不同语言由自己编译器,生成符合 JSR-292 JVM规范的字节码文件,即可在 Java 虚拟机中运行  多语言混合编程: Java 平台上的多语言混合编程正成为主流,通过特定领域的语言去解决特定领域的问题是当前软件开发应对日趋复杂的项目需求的一个方向 每个应

    2024年02月03日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包