zoukankan      html  css  js  c++  java
  • 【翻译】IdentityServer4:基于资源的配置

    这篇文章基于https://leastprivilege.com/2016/12/01/new-in-identityserver4-resource-based-configuration/进行翻译,解释了IdentityServer4中关于资源(Rerource)的原理。

    以下是一些涉及到的术语和翻译的映射关系:

    客户端---client

    资源---Resource

    作用域/范围---Scope

    Api资源---ApiResource

    Identity资源/身份资源---IdentityResource

    原文的题目为New in IdentityServer4: Resource-based Configuration,Resource是对于Scope这个概念的进一步抽象。以下为翻译,需要注意的是Scope被翻译为作用域,Resource被翻译成资源。但有一些地方我为了清楚的表示出其中的术语,还是会有意的在小括号中标记出相关的单词。

    对于RC4(早前IdentityServer4的一个预览版本),我们决定为资源(以前称为作用域)重新设计配置对象模型。

    我知道,我知道——我们不应该在达到RC状态后做出根本性的突破性的改变——但是,嘿——我们有了“DNX”时刻,意识到我们要么现在改变,要么永远不改变。

    我们为啥要这么干?

    在过去的几年里,我们花了大量的时间向数百名参加培训班的学生、会议的与会者、开发人员以及来自各行各业的客户解释OpenID Connect和基于OAuth 2.0的体系结构。

    虽然大多数概念都非常清楚,而且完全有意义,但是对于大多数人来说,作用域是最容易混淆的部分。作用域的抽象本质,以及术语Scope在OpenID Connect和OAuth 2.0中的含义有所不同,使得这个概念很难理解。

    也许部分原因是我们的错误,我们在对待对象模型和抽象(接口)层面上保持了比较相近的概念(意思是说之前建立的这个接口或抽象还是有一些抽象,不确切),同时,我们将这个概念强加给了IdentityServer的每个用户。

    长话短说——每次我需要解释Scope时,我都会说“Scope是客户想要访问的资源”之类的话。“有两种类型的Scope:与标识(就是现在的IdentityResource)相关的Scope和api(就是现在的ApiResource)……”

    这让我们思考在IdentityServer中引入资源(resource)的概念,并去掉作用域(Scope)是否更有意义。

    我们干了啥?

    在RC4之前——我们的配置对象模型有三个主要部分:用户、客户端和作用域(Scope)(作用域有两种类型——标识和资源——以及它们之间的一些重叠设置)。

    从RC4开始——配置模型不再是顶级概念,取而代之的是身份资源和API资源。

    我们认为这是一种更自然的方式(和语言)来建模一个典型的基于令牌的系统(token-based system)。

    在我们新的文档中:

    1、用户


    用户是一个使用已注册的客户端(client)访问资源的人类。

    2、客户端

    客户端是一个软件,它从IdentityServer(认证服务器)请求令牌——用于对用户进行身份验证(请求标识令牌,id_token)

    或用于访问资源(请求访问令牌,access_token)。客户机必须首先在IdentityServer注册,然后才能请求令牌。

    3、资源

    资源是你利用IdentityServer(认证服务器)进行保护的对象,也就是说它是一种被保护的东西。它可以是用户的信息(比如名字、电话、生日等)或者是API。

    talk is cheap,show me the code,我们怎么干的?

    在RC4之前,你可能会使用作用域(Scope)存储来返回作用域的平面列表(意思就是一个List<Scope>里面即放了关于API的Scope,又放了关于身份标识的Scope)。现在新的资源存储处理两种不同的资源类型:IdentityResource和ApiResource。

    让我们从Identityresource开始--标准的Scope定义的关于Identity的Scope列表如下:‘

    public static IEnumerable<Scope> GetIdentityScopes()
    {
        return new List<Scope>
        {
            StandardScopes.OpenId,
            StandardScopes.Profile
        };
    }

    上面那种换成新的写法如下:

    public static IEnumerable<IdentityResource> GetIdentityResources()
    {
        return new List<IdentityResource>
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile()
        };
    }

    也没啥大不一样的地方,现在,让我们用相关的Claims声明来定义一些IdentityResource:

    var customerProfile = new IdentityResource(
        name:        "profile.customer",
        displayName: "Customer profile",
        claimTypes:  new[] { "name", "status", "location" });

    以上这样的定义就会使用于90%的场景。如果需要调整细节,可以在IdentityResource类上设置各种属性。

    然后再来看看ApiResource,之前你需要像下面这种的定义一个Api的Scope列表:

    public static IEnumerable<Scope> GetScopes()
    {
        return new List<Scope>
        {
            new Scope
            {
                Name = "api1",
                DisplayName = "My API #1",
     
                Type = ScopeType.Resource
            }
        };
    }

    现在是这样:

    public static IEnumerable<ApiResource> GetApis()
    {
        return new[]
        {
            new ApiResource("api1", "My API #1")
        };
    }

    同样,对于简单的情况,没有太大的区别。当你有一些高级需求时,比如具有多个作用域的api(可能根据作用域(Scope)有不同的声明(Claim))和对自省/反射(introspection)的支持时,ApiResource对象模型开始变得更加强大,例如:

    public static IEnumerable<ApiResource> GetApis()
    {
        return new[]
        {
            new ApiResource
            {
                Name = "calendar",
     
                // secret for introspection endpoint
                ApiSecrets =
                {
                    new Secret("secret".Sha256())
                },
     
                // claims to include in access token
                UserClaims =
                {
                    JwtClaimTypes.Name,
                    JwtClaimTypes.Email
                },
     
                // API has multiple scopes
                Scopes =
                {
                    new Scope
                    {
                        Name = "calendar.read_only",
                        DisplayName = "Read only access to the calendar"
                    },
                    new Scope
                    {
                        Name = "calendar.full_access",
                        DisplayName = "Full access to the calendar",
                        Emphasize = true,
     
                        // include additional claim for that scope
                        UserClaims =
                        {
                            "status"
                        }
                    }
                }
            };
        }

    我们颠倒了配置方法,现在你建模的是API(可能有作用域),而不是作用域(刚好表示API)。

    我们更喜欢新模型,因为它反映了如何更好地构建基于令牌的系统。我们希望你也喜欢它;)

  • 相关阅读:
    【转】海量数据处理算法-Bloom Filter
    【c++】【转】结构体字节对齐
    【APUE】信号量、互斥体和自旋锁
    【python】Python的字典get方法:从字典中获取一个值
    【python】Python中*args 和**kwargs的用法
    【python】super()
    【algorithm】尾递归
    什么时候必须使用初始化列表
    【APUE】wait与waitpid函数
    【APUE】孤儿进程与僵死进程
  • 原文地址:https://www.cnblogs.com/pangjianxin/p/10095987.html
Copyright © 2011-2022 走看看