IdentityServer3 v1文档

IdentityServer3javascript

目录css

目录 1html

第一章 IdentityServer3 1.x 5前端

v 超连接 5html5

Ø 概述 5java

Ø 配置 5git

Ø 端点 5github

Ø 先进的 5web

Ø 实体框架支持客户、范围和操做数据 6redis

Ø ws - federation 6

Ø 资源 6

第二章 概述 6

v 大局 6

v 术语 7

v OpenID提供者链接(凤凰社) 8

v 客户端 8

v 用户 8

v 范围 8

Ø 身份范围 8

Ø 资源范围 9

第三章 认证/令牌请求 9

v 身份标识 9

v 访问令牌 9

v 特性和规格 9

v 包装和构建 9

Ø 核心 9

Ø 配置商店 9

Ø 用户存储 9

Ø 插件 9

Ø 访问令牌验证中间件 10

v 开发构建 10

Ø 建立最简单的OAuth2受权服务器,客户端和API 10

Ø 设置IdentityServer 10

Ø 注册的API 10

Ø 注册客户端 10

Ø 配置IdentityServer 11

Ø 托管IdentityServer 12

v 添加一个API 12

Ø 建立网络主机 12

Ø 添加一个控制器 12

Ø 添加启动 12

v 添加一个控制台客户 13

v 添加一个用户 13

Ø 添加一个用户服务 13

Ø 添加一个客户 14

Ø 更新的API 15

Ø 更新客户端 15

v 下一步要作什么 16

v 第1部分- MVC身份验证和受权 16

Ø 建立web应用程序 16

Ø 添加IdentityServer 17

Ø 配置IdentityServer -客户 17

Ø 配置IdentityServer——用户 18

Ø 添加启动 18

Ø RAMMFAR 19

v 添加和配置OpenID身份验证链接中间件 19

v 添加一个受保护的资源和Claims 19

Ø 身份验证和Claims 20

Ø 添加角色和范围 20

Ø 改变了中间件配置要求的角色 21

Ø 要求转换 21

Ø 受权 23

Ø 资源受权 23

Ø 角色权限 24

Ø 更多的受权和处理拒绝访问场景 24

Ø 添加注销 25

Ø 添加谷歌身份验证 26

v 第2部分-添加和调用Web API 27

Ø 添加Web API项目 27

Ø 添加一个测试控制器 28

Ø 链接在启动Web API和安全 28

Ø 注册在IdentityServer API 29

Ø 注册一个Web API客户端 30

Ø 调用API 30

Ø 表明用户调用的API 32

第四章 配置 33

v 概述 33

v IdentityServer选项 34

v 服务工厂 34

v 强制性的 35

v 强制性的生产场景(但默认内存中实现) 35

v 可选(能够更换,但有默认的实现) 35

v 内存中的工厂 36

第五章 客户 36

Ø 例如:为隐式流配置客户端 37

Ø 例如:为资源全部者流配置客户端 38

v 范围和Claims 39

Ø Thinktecture.IdentityServer.Core.Models.Scope类的模型OpenID链接或OAuth2范围。 39

v 身份验证选项 40

v 身份提供者 41

v 添加ws - federation身份提供者 42

v HSTS 43

v CORS 43

v 歌珥政策服务 43

Ø 提供实现 43

v 弃用:CorsPolicy 43

Ø CorsPolicy 43

v 日志记录 44

v 配置诊断 44

v 配置系统 诊断提供者 44

v 配置TraceSource提供者 45

v 插装本身的代码 45

v 事件 45

v 配置事件 45

第六章 端点 46

v 受权/身份验证端点 46

Ø 支持参数 46

Ø 例子 46

v 令牌端点 47

Ø 支持参数 47

Ø 身份验证 47

Ø 例子 47

v 用户信息端点 48

Ø 例子 48

v 发现端点 48

Ø 例子 48

v 注销端点 48

v 令牌撤销 48

v 访问令牌验证端点 49

Ø 例子 49

v 身份令牌验证端点 49

Ø 例子 49

v CSP端点 49

第七章 先进的 50

v 刷新令牌 50

Ø 设置在客户端类 50

Ø 使用 50

Ø 样品 50

v 定制服务 50

v 强制性的服务 50

v 注册定制服务 50

Ø 服务清理 51

第八章 依赖注入 51

v 注入IdentityServer服务 51

v 注入定制服务 52

Ø 没有一个接口定制服务 52

v 建立自定义 53

Ø 得到其余依赖项 53

Ø 叫依赖 53

v 实例化与登记模式 53

v 客户端缓存结果、范围和用户存储 54

v 默认的缓存 54

v 自定义缓存 54

v 自定义视图 54

Ø 默认视图服务 54

Ø 自定义视图服务 55

v 本地化的消息 56

v CSP 56

Ø CspOptions 56

v 用户服务 56

v 身份验证 57

Ø 验证结果 57

第九章 部署 58

v 数据保护 58

v 终止SSL 58

v 签名密钥 59

v 配置数据 59

v 操做数据 59

v 缓存 59

第十章 实体框架支持客户、范围和操做数据 59

v 概述 59

v 配置客户机和范围 59

v 操做数据 59

v 客户和范围 59

v 商店 59

Ø ClientStore 59

Ø ScopeStore 59

v 登记 59

第十一章 操做数据 60

v 数据清理 60

第十二章 模式变化和迁移 60

v dbcontext 60

v 使迁移 60

第十三章 ws - federation 61

v 添加ws - federation支持 61

v 定义依赖方 62

v 端点 63

v 登陆/出 63

v 元数据 63

第十四章 资源 63

v 资源 63

Ø 规范 64

Ø 文章 64

Ø 视频 64

Ø 培训 64

v 社区插件 64

第十五章 中间件为外部认证 64

v 微软的武士刀 64

v SAML2p 64

v 其余社区的贡献 65

 

 

第一章IdentityServer3 1.x

v 超连接

Ø 概述

大局

术语

特性和规格

包装

开始:建立最简单的OAuth2受权服务器,客户端和API

开始:MVC认证& Web api

Ø 配置

概述

选项

服务工厂

内存中的工厂

客户

范围和Claims

身份验证选项

身份提供者

hst

歌珥

日志记录

事件

Ø 端点

受权/身份验证

令牌

用户信息

发现

注销

令牌撤销

访问令牌验证

身份令牌验证

CSP错误报告

Ø 先进的

刷新令牌

注册服务

DI的服务

客户端缓存,范围和用户存储

自定义视图

本地化的消息

CSP

用户服务

部署

Ø 实体框架支持客户、范围和操做数据

概述

客户和范围

操做数据

模式变化和迁移

Ø ws - federation

添加支持ws - federation

定义依赖方

端点

Ø 资源

概述

社区插件

中间件为外部认证

 

 

 

第二章概述

v 大局

大多数现代应用程序看起来或多或少是这样的:

 

典型的交互: 

l 浏览器与web应用程序通讯 

l Web应用程序与Web api(有时本身,有时表明一个用户) 

l 基于浏览器的应用程序与web api通讯 

l 本机应用程序与web api通讯 

l 基于服务器的应用程序与web api通讯  

l Web apiWeb api(有时本身,有时表明一个用户)

 

一般每一层(中间层和后端,前端)和保护资源 实现身份验证和/或受权,一般针对同一用户存储。

这就是为何咱们没有实现这些基本安全功能的业务应用程序/端点自己而是关键功能的外包服务,安全令牌服务。

这将致使如下安全架构和使用协议:

 

这将安全问题划分为两个部分。

u 身份验证

身份验证是必要的,当一个应用程序须要知道当前用户的身份。 一般这些应用程序表明用户管理数据,须要确保用户只能 他被容许访问数据。 最多见的例子(经典)web应用程序 但本机和JS-based应用程序也须要进行身份验证。

最多见的身份验证协议SAML2p,ws - federation,OpenID链接——SAML2p 最受欢迎和最普遍的部署。

OpenID链接是最新的三个,但通常认为是,由于它有将来 现代应用最有潜力的产业。 它从一开始就为移动应用程序场景 和被设计成API友好。

u API访问

应用程序有两个基本方法,它们与api使用应用程序标识或受权用户的身份。 有时两方面须要的总和。

OAuth2是一种协议,它容许应用程序请求访问令牌从安全令牌服务和使用它们 与api。 这下降了复杂性在客户机应用程序的api 能够集中的身份验证和受权。

OpenIDOAuth2——更好的联系在一块儿

OpenID链接和OAuth2很是类似——事实上OpenID是一个链接扩展OAuth2之上。 这意味着您能够将两个基本安全问题-认证和API访问到一个单独的协议 一般一个往返安全令牌服务。

这就是为何咱们相信OpenID的组合链接和安全的现代OAuth2是最好的方法 应用程序在可预见的将来。 IdentityServer3是这两个协议的一个实现 高度优化的解决今天的移动的典型安全问题,本机和web应用程序。

v 术语

规范、文档对象模型使用一个特定的术语,你应该知道的。

 

v OpenID提供者链接(凤凰社)

IdentityServer OpenID提供者链接,它实现了OpenID链接协议(以及OAuth2)

不一样的文献使用不一样的条款相同的角色,你也可能找到安全令牌服务身份提供者,受权服务器,IP-STS等等。

但总而言之都是同样的:一个软件问题给客户的安全令牌。

IdentityServer有不少工做和功能,包括: 

l 验证用户使用本地账户存储或经过外部身份提供者 

l 提供会话管理和单点登陆 

l 管理和认证的客户 

l 问题客户身份和访问令牌 

l 验证令牌 

v 客户端

客户端是一个软件,请求令牌从IdentityServer——对一个用户进行身份验证或 一般用于访问资源(也称为依赖方或RP)。 客户端必须注册与OP

客户是web应用程序的例子,本地移动或桌面应用程序,水疗,服务器进程等。

v 用户

用户是一我的类,使用一个注册客户机来访问他或她的数据。

v 范围

做用域标识符为客户想要访问的资源。 这个标识符在一个发送给OP 身份验证或令牌的请求。

默认状况下容许每一个客户机请求令牌为每一个范围,可是你能够限制。

他们有两种口味。

Ø 身份范围

请求关于用户的标识信息(又名声称),如他的名字或电子邮件地址被建模为一个范围的OpenID链接。

若有一个范围profile首选,包括名字、姓、用户名、性别、证件照以及更多。 你能够读到标准范围在这里你能够建立本身的范围IdentityServer模型本身的需求。

Ø 资源范围

资源范围肯定web api(也称为资源服务器)——你能够如命名范围calendar表明你的日历API

第三章认证/令牌请求

客户请求令牌的相机会取决于请求的范围,OP会返回一个身份令牌,一个访问令牌,或二者兼而有之。

v 身份标识

能够经过客户端验证身份令牌。

它包含有关用户的信息和细节在OP用户身份验证。 身份令牌表明一个成功的身份验证。

v 访问令牌

一个访问令牌能够由资源进行验证。

客户请求访问令牌和转发他们的API。 访问令牌包含客户端和用户信息(若是存在)。 api使用这些信息来受权访问他们的数据。

v 特性和规格

IdentityServer实现如下规格:

l OpenID链接核心1.0(规范)

l 基本的、隐含的和混合流

l OpenID链接发现1.0规范)

l OpenID链接会话管理1.0 - 22(草案规范)

l OAuth 2.0(RFC 6749)

l 受权代码、隐式资源全部者密码凭证和客户端凭证

l OAuth 2.0不记名使用令牌(RFC 6750)

l OAuth 2.0多种反应类型(规范)

l OAuth 2.0表单Post响应模式(规范)

l OAuth 2.0令牌撤销(RFC 7009)

v 包装和构建

IdentityServernuget包的数量。

Ø 核心

nuget | github

包含核心IdentityServer对象模型、服务和服务器。 只包含核心支持内存配置和用户的商店,可是你能够经过配置插件支持其余商店。 这是另外一个回购和包。

Ø 配置商店

存储配置数据(客户和范围)以及运行时数据(赞成,令牌处理,刷新令牌)

实体框架nuget | github

(社区贡献)MongoDbgithub

Ø 用户存储

支持身份管理库。

MembershipReboot nuget | github

ASP.Net Identity nuget | github

Ø 插件

协议插件。

ws - federationnuget | github

Ø 访问令牌验证中间件

OWIN中间件api。 提供了一种简便的方法来验证访问令牌和实施范围的要求。

nuget | github

v 开发构建

此外,咱们发布dev /临时构建MyGet。 Visual Studio下面添加到你若是你想给他们一个尝试:

https://www.myget.org/F/identity/

Ø 建立最简单的OAuth2受权服务器,客户端和API

这个介绍的目的是建立简单的IdentityServer安装做为一个OAuth2受权服务器。 这是应该让你开始的一些基本特性和配置选项(能够找到完整的源代码在这里)。 还有其余更高级的演练的文档以后你能够作。 本教程包括:  

l 建立一个自托管IdentityServer 

l 为应用程序设置客户服务通讯使用应用程序账户和表明一个用户 

l 注册一个API 

l 请求访问令牌 

l 调用一个API 

l 验证一个访问令牌

 

Ø 设置IdentityServer

首先,咱们将建立一个控制台主机和设置IdentityServer

首先建立一个标准的控制台应用程序并添加IdentityServer经过nuget:

install-package Thinktecture.IdentityServer3

Ø 注册的API

api建模为范围,你须要注册全部api,你但愿可以请求访问令牌。 为咱们建立一个类返回的列表Scope:

using Thinktecture.IdentityServer.Core.Models;

static class Scopes{

    public static List<Scope> Get()

    {

        return new List<Scope>

        {

            new Scope

            {

                Name = "api1"

            }

        };

    }}

Ø 注册客户端

如今咱们想注册一个单一的客户端。 这个客户端能够请求的令牌api1范围。 对于咱们的第一次迭代,就没有人类参与和客户端只会请求令牌 表明自己(想一想机对机通讯)。 稍后咱们将添加一个用户。

这个客户咱们配置如下事情: 

l 显示名称和id(惟一的名称) 

l 客户端秘密(用于验证客户端对令牌端点) 

l 流(客户端凭证流在这种状况下) 

l 所谓的参考标记的使用。 参考标记不须要签名证书。 

using Thinktecture.IdentityServer.Core.Models;

static class Clients{

    public static List<Client> Get()

    {

        return new List<Client>

        {

            // no human involved

            new Client

            {

                ClientName = "Silicon-only Client",

                ClientId = "silicon",

                Enabled = true,

                AccessTokenType = AccessTokenType.Reference,

 

                Flow = Flows.ClientCredentials,

                ClientSecrets = new List<ClientSecret>

                {

                    new ClientSecret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())

                }

            }

        };

    }}

Ø 配置IdentityServer

IdentityServer被实现为OWIN中间件。 中配置的Startup类使用UseIdentityServer扩展方法。 下面的代码片断设置一个梗概服务器范围和客户。 咱们还创建了一个空列表的用户,咱们稍后会添加用户。

using Thinktecture.IdentityServer.Core.Configuration;using Thinktecture.IdentityServer.Core.Services.InMemory;

class Startup{

    public void Configuration(IAppBuilder app)

    {

        var factory = InMemoryFactory.Create(

            scopes:  Scopes.Get(),

            clients: Clients.Get(),

            users:   new List<InMemoryUser>());

 

        var options = new IdentityServerOptions

        {

            Factory = factory

        };

 

        app.UseIdentityServer(options);

    }}

Ø 托管IdentityServer

最后一步是主机IdentityServer。 为此咱们将武士刀自托管包添加到控制台应用程序:

install-package Microsoft.Owin.SelfHost

添加如下代码Program.cs:

using Microsoft.Owin.Hosting;using Thinktecture.IdentityServer.Core.Logging;

static void Main(string[] args){

    LogProvider.SetCurrentLogProvider(new DiagnosticsTraceLogProvider());

 

    using (WebApp.Start<Startup>("https://localhost:44333"))

    {

        Console.WriteLine("server running...");

        Console.ReadLine();

    }}

当您运行控制台应用程序,您应该看到一些诊断输出server running...

v 添加一个API

在这一部分,咱们将添加一个简单的web API,它被配置为从IdentityServer咱们只是须要一个访问令牌。

Ø 建立网络主机

添加一个新的ASP.NET Web Application解决方案和选择Empty选项(没有框架的引用)

添加必要的nuget:

install-package Microsoft.Owin.Host.SystemWeb

install-package Microsoft.AspNet.WebApi.Owin

install-package Thinktecture.IdentityServer3.AccessTokenValidation

Ø 添加一个控制器

添加这个简单的测试控制器:

[Route("test")]public class TestController : ApiController{

    public IHttpActionResult Get()

    {

        var caller = User as ClaimsPrincipal;

 

        return Json(new

        {

            message = "OK computer",

            client =  caller.FindFirst("client_id").Value

        });

    }}

User财产的控制器给你访问的访问令牌。

Ø 添加启动

添加如下Startup类设置web api和配置与IdentityServer信任

using Thinktecture.IdentityServer.AccessTokenValidation;

public void Configuration(IAppBuilder app){

    // accept access tokens from identityserver and require a scope of 'api1'

    app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions

        {

            Authority = "https://localhost:44333",

            RequiredScopes = new[] { "api1" }

        });

 

    // configure web api

    var config = new HttpConfiguration();

    config.MapHttpAttributeRoutes();

 

    // require authentication for all controllers

    config.Filters.Add(new AuthorizeAttribute());

 

    app.UseWebApi(config);}

试着打开浏览器并访问测试控制器,您应该看到一个401由于必要的访问令牌是失踪。

v 添加一个控制台客户

在接下来的部分,咱们将添加一个简单的控制台客户端请求一个访问令牌和使用进行身份验证的api

首先添加一个新的控制台项目和安装nugetOAuth2客户机助手库:

install-package Thinktecture.IdentityModel.Client

第一个代码片断使用客户端证书请求访问令牌:

using Thinktecture.IdentityModel.Client;

static TokenResponse GetToken(){

    var client = new OAuth2Client(

        new Uri("https://localhost:44333/connect/token"),

        "silicon",

        "F621F470-9731-4A25-80EF-67A6F7C5F4B8");

 

    return client.RequestClientCredentialsAsync("api1").Result;}

第二个代码段调用API使用访问令牌:

using Thinktecture.IdentityModel.Client;

static void CallApi(TokenResponse response){

    var client = new HttpClient();

    client.SetBearerToken(response.AccessToken);

 

    Console.WriteLine(client.GetStringAsync("http://localhost:14869/test").Result);}

若是你叫两个片断,您应该看到{"message":"OK computer","client":"silicon"}在您的控制台。

v 添加一个用户

到目前为止,客户端请求的访问令牌自己,没有用户。 让咱们介绍一我的。

Ø 添加一个用户服务

用户服务管理用户,对于此示例,咱们将使用简单的内存的用户服务。 首先咱们须要定义一些用户:

using Thinktecture.IdentityServer.Core.Services.InMemory;

static class Users{

    public static List<InMemoryUser> Get()

    {

        return new List<InMemoryUser>

        {

            new InMemoryUser

            {

                Username = "bob",

                Password = "secret",

                Subject = "1"

            },

            new InMemoryUser

            {

                Username = "alice",

                Password = "secret",

                Subject = "2"

            }

        };

    }}

UsernamePassword用于验证用户Subject是该用户的惟一标识符,将嵌入到访问令牌。

Startup配置方法取代所说空的用户列表Get方法。

替换:csharp users: new List<InMemoryUser>()); :csharp users: Users.Get());

Ø 添加一个客户

接下来,咱们将添加一个客户端定义使用流resource owner password credential grant。 这个流容许客户端用户的用户名和密码发送到令牌服务,获得一个访问令牌。

在总Clients类是这样的:

using Thinktecture.IdentityServer.Core.Models;

static class Clients{

    public static List<Client> Get()

    {

        return new List<Client>

        {

            // no human involved

            new Client

            {

                ClientName = "Silicon-only Client",

                ClientId = "silicon",

                Enabled = true,

                AccessTokenType = AccessTokenType.Reference,

 

                Flow = Flows.ClientCredentials,

                ClientSecrets = new List<ClientSecret>

                {

                    new ClientSecret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())

                }

            },

 

            // human is involved

            new Client

            {

                ClientName = "Silicon on behalf of Carbon Client",

                ClientId = "carbon",

                Enabled = true,

                AccessTokenType = AccessTokenType.Reference,

 

                Flow = Flows.ResourceOwner,

                ClientSecrets = new List<ClientSecret>

                {

                    new ClientSecret("21B5F798-BE55-42BC-8AA8-0025B903DC3B".Sha256())

                }

            }

        };

    }}

Ø 更新的API

当一我的类,将包含访问令牌sub唯一标识用户。 让咱们把这个小修改API控制器:

[Route("test")]public class TestController : ApiController{

    public IHttpActionResult Get()

    {

        var caller = User as ClaimsPrincipal;

 

        var subjectClaim = caller.FindFirst("sub");

        if (subjectClaim != null)

        {

            return Json(new

            {

                message = "OK user",

                client = caller.FindFirst("client_id").Value,

                subject = subjectClaim.Value

            });

        }

        else

        {

            return Json(new

            {

                message = "OK computer",

                client = caller.FindFirst("client_id").Value

            });

        }

    }}

Ø 更新客户端

下添加一个新的方法给客户端请求一个访问令牌表明用户:

static TokenResponse GetUserToken(){

    var client = new OAuth2Client(

        new Uri("https://localhost:44333/connect/token"),

        "carbon",

        "21B5F798-BE55-42BC-8AA8-0025B903DC3B");

 

    return client.RequestResourceOwnerPasswordAsync("bob", "secret", "api1").Result;}

如今尝试两种方法的请求令牌和检查要求和API的回应。

该项目名称为Simplest OAuth2 Walkthrough。

v 下一步要作什么

这演练了一个很是简单的OAuth2场景。 下一个你能够试试: 

l 其余流,如隐式、代码或混合。 他们都是推进者等高级场景联合会和外部的身份 

l 链接到您的用户数据库,经过编写本身的用户服务或使用咱们的开箱即用的支持ASP.Net Identity和MembershipReboot 

l 客户端和范围配置存储在一个数据存储。 咱们有现成的实体框架支持。

l 使用OpenID链接和添加身份验证和身份令牌标识范围

l 本教程将引导您完成必要的步骤来获得一个最小IdentityServer启动并运行。 为简单起见,咱们将主机IdentityServer和客户端在同一web应用程序,这可能不是一个很是现实的场景中,但可让你开始没有使它太复杂。

能够找到完整的源代码在这里

v 第1部分- MVC身份验证和受权

在第一部分,咱们将建立一个简单的MVC应用程序并经过IdentityServer添加身份验证。 而后咱们会仔细看看Claims,Claims转换和受权

Ø 建立web应用程序

Visual Studio 2013,建立一个标准的MVC应用程序和身份验证设置为无身份验证

 

如今您能够切换项目SSL使用属性窗口:

 

 

重要的别忘了更新在您的项目中开始URL属性。

Ø 添加IdentityServer

IdentityServer基于OWIN /刀和分布式Nuget包。 将其添加到新建立的web主机,安装如下两个方案:

install-package Microsoft.Owin.Host.Systemweb

install-package Thinktecture.IdentityServer3

Ø 配置IdentityServer -客户

IdentityServer须要一些关于客户的信息支持,这能够简单地提供使用Client对象:

public static class Clients{

    public static IEnumerable<Client> Get()

    {

        return new[]

        {

            new Client 

            {

                Enabled = true,

                ClientName = "MVC Client",

                ClientId = "mvc",

                Flow = Flows.Implicit,

 

                RedirectUris = new List<string>

                {

                    "https://localhost:44319/"

                }

            }

        };

    }}

Ø 配置IdentityServer——用户

接下来,咱们将添加一些用户再次IdentityServer——这能够经过提供一个简单的c#类。 你能够从任何数据存储和检索用户信息咱们提供开箱即用的支持ASP。 网络身份和MembershipReboot

public static class Users{

    public static List<InMemoryUser> Get()

    {

        return new List<InMemoryUser>

        {

            new InMemoryUser

            {

                Username = "bob",

                Password = "secret",

                Subject = "1",

 

                Claims = new[]

                {

                    new Claim(Constants.ClaimTypes.GivenName, "Bob"),

                    new Claim(Constants.ClaimTypes.FamilyName, "Smith")

                }

            }

        };

    }}

Ø 添加启动

IdentityServer在启动配置类。 这里咱们提供关于客户的信息,用户,范围签名证书和其余一些配置选项。 在生产中应该从Windows证书存储加载签名证书或其余担保来源。 在这个示例中,咱们简单地添加它到项目文件(您能够下载测试证书在这里。 将其添加到项目并设置其构建行动Copy to output

对信息如何加载证书从Azure网站看到在这里

public class Startup{

    public void Configuration(IAppBuilder app)

    {

        app.Map("/identity", idsrvApp =>

            {

                idsrvApp.UseIdentityServer(new IdentityServerOptions

                {

                    SiteName = "Embedded IdentityServer",

                    SigningCertificate = LoadCertificate(),

 

                    Factory = InMemoryFactory.Create(

                        users  : Users.Get(),

                        clients: Clients.Get(),

                        scopes : StandardScopes.All)

                });

            });

    }

 

    X509Certificate2 LoadCertificate()

    {

        return new X509Certificate2(

            string.Format(@"{0}\bin\identityServer\idsrv3test.pfx", AppDomain.CurrentDomain.BaseDirectory), "idsrv3test");

    }}

在这一点上你有一个功能齐全的IdentityServer你能够浏览发现端点检查配置:

 

Ø RAMMFAR

最后一件事,请不要忘了RAMMFAR添加到您的网站。 配置,不然咱们的一些嵌入式资产由IIS将不能正确加载:

<system.webServer>

  <modules runAllManagedModulesForAllRequests="true" /></system.webServer>

v 添加和配置OpenID身份验证链接中间件

OIDC验证添加到MVC应用程序中,咱们须要添加两个包:

install-package Microsoft.Owin.Security.Cookies

install-package Microsoft.Owin.Security.OpenIdConnect

在启动配置饼干中间件。 cs的默认值:

install-package Microsoft.Owin.Security.Cookies

install-package Microsoft.Owin.Security.OpenIdConnect 

在启动配置饼干中间件。 cs的默认值: 配置,不然咱们的一些嵌入式资产由IIS将不能正确加载:

 

app.UseCookieAuthentication(new CookieAuthenticationOptions

    {

        AuthenticationType = "Cookies"

    });

OpenID中间件(也在StartUp.cs)链接到咱们的嵌入式版本的IdentityServer和使用先前配置的客户端配置:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions

    {

        Authority = "https://localhost:44319/identity",

        ClientId = "mvc",

        RedirectUri = "https://localhost:44319/",

        ResponseType = "id_token",

 

        SignInAsAuthenticationType = "Cookies"

    });

v 添加一个受保护的资源和Claims

启动认证与IdentityServer您须要建立一个受保护的资源,如经过增长全球受权过滤器。 对于咱们的示例,咱们将简单地保护About行动上的Home控制器。 此外咱们将交出声称视图中咱们能够看到号称IdentityServer发出的有:

[Authorize]public ActionResult About(){

    return View((User as ClaimsPrincipal).Claims);}

 相应的观点是这样的:

@model IEnumerable<System.Security.Claims.Claim>

<dl>

    @foreach (var claim in Model)

    {

        <dt>@claim.Type</dt>

        <dd>@claim.Value</dd>

    }</dl>

Ø 身份验证和Claims

点击连接将触发身份验证。 IdentityServer将显示登陆屏幕并发送一个令牌回主应用程序。 OpenID Connect中间件验证令牌,提取并将其传送给Cookies中间件,这将反过来设置身份验证cookie。 用户如今签署。  

Ø 添加角色和范围

在下一步咱们要添加一些声称咱们的用户角色,稍后咱们将使用受权。

如今咱们获得了OIDC标准范围,让咱们定义一个角色范围,包括角色要求并添加到标准范围:

public static class Scopes{

    public static IEnumerable<Scope> Get()

    {

        var scopes = new List<Scope>

        {

            new Scope

            {

                Enabled = true,

                Name = "roles",

                Type = ScopeType.Identity,

                Claims = new List<ScopeClaim>

                {

                    new ScopeClaim("role")

                }

            }

        };

 

        scopes.AddRange(StandardScopes.All);

 

        return scopes;

    }}

也改变了工厂Startup

Factory = InMemoryFactory.Create(

    users: Users.Get(),

    clients: Clients.Get(),

    scopes: Scopes.Get())

 

接下来,咱们添加两个角色声称鲍勃:

public static class Users{

    public static IEnumerable<InMemoryUser> Get()

    {

        return new[]

        {

            new InMemoryUser

            {

                Username = "bob",

                Password = "secret",

                Subject = "1",

 

                Claims = new[]

                {

                    new Claim(Constants.ClaimTypes.GivenName, "Bob"),

                    new Claim(Constants.ClaimTypes.FamilyName, "Smith"),

                    new Claim(Constants.ClaimTypes.Role, "Geek"),

                    new Claim(Constants.ClaimTypes.Role, "Foo")

                }

            }

        };

    }}

Ø 改变了中间件配置要求的角色

默认状况下,OIDC中间件要求两个范围:openidprofile——这就是为何IdentityServer包括Claims主体和名称。 如今咱们添加一个请求roles范围:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions

    {

        Authority = "https://localhost:44319/identity",

 

        ClientId = "mvc",

        Scope = "openid profile roles",

        RedirectUri = "https://localhost:44319/",

        ResponseType = "id_token",

 

        SignInAsAuthenticationType = "Cookies"

    });

成功的身份验证以后,如今您应该看到角色收集Claims在用户的Claims:

 

Ø 要求转换

检查声明这个页面时,您将注意到两件事:一些声称奇怪的长类型名称和有更多的比你可能须要在您的应用程序。

长的声明名称来自微软的JWT处理程序试图一些Claims类型映射到.netClaimTypes类类型。 你能够关掉这个行为与如下代码行(Startup)

这也意味着你须要调整配置anti-CSRF保护新的独特sub申请类型:

AntiForgeryConfig.UniqueClaimTypeIdentifier = Constants.ClaimTypes.Subject;JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();

声称将如今看起来像这样:

 

这是一个进步,可是仍有一些低水平协议声称,固然是不须要经过典型的业务逻辑。 将原始输入Claims转化为特定于应用程序的过程Claims称为Claims转换。 在这个过程当中你把传入的说法,决定你想要号称也许须要联系其余数据存储检索更声称所需的应用程序。

OIDC中间件有通知,您可使用它们来作Claims转型——由此产生的Claims将存储在cookie:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions

    {

        Authority = "https://localhost:44319/identity",

 

        ClientId = "mvc",

        Scope = "openid profile roles",

        RedirectUri = "https://localhost:44319/",

        ResponseType = "id_token",

 

        SignInAsAuthenticationType = "Cookies",

        UseTokenLifetime = false,

 

        Notifications = new OpenIdConnectAuthenticationNotifications

        {

            SecurityTokenValidated = async n =>

                {

                    var id = n.AuthenticationTicket.Identity;

 

                    // we want to keep first name, last name, subject and roles

                    var givenName = id.FindFirst(Constants.ClaimTypes.GivenName);

                    var familyName = id.FindFirst(Constants.ClaimTypes.FamilyName);

                    var sub = id.FindFirst(Constants.ClaimTypes.Subject);

                    var roles = id.FindAll(Constants.ClaimTypes.Role);

 

                    // create new identity and set name and role claim type

                    var nid = new ClaimsIdentity(

                        id.AuthenticationType,

                        Constants.ClaimTypes.GivenName,

                        Constants.ClaimTypes.Role);

 

                    nid.AddClaim(givenName);

                    nid.AddClaim(familyName);

                    nid.AddClaim(sub);

                    nid.AddClaims(roles);

 

                    // add some other app specific claim

                    nid.AddClaim(new Claim("app_specific", "some data"));                   

 

                    n.AuthenticationTicket = new AuthenticationTicket(

                        nid,

                        n.AuthenticationTicket.Properties);

                }

        }

    });

添加上面的代码以后,咱们要求的设置如今看起来像这样:

Ø 受权

如今咱们已经认证和一些Claims,咱们能够开始添加简单的受权规则。

MVC有一个内置的属性[Authorize]须要经过身份验证的用户,您还可使用此属性来标注角色从属关系的要求。 咱们不推荐这种方法,由于这一般会致使代码混合业务/控制器逻辑和受权策略的担心。 咱们不推荐从控制器分离受权逻辑致使清洁代码和更好的可测试性(阅读更多在这里)

Ø 资源受权

添加新受权的基础设施和新属性,咱们添加一个Nuget

install-package Thinktecture.IdentityModel.Owin.ResourceAuthorization.Mvc

接下来咱们注释Contact行动上的Home控制器和一个属性,表示这一行动将执行ReadContactDetails资源:

[ResourceAuthorize("Read", "ContactDetails")]public ActionResult Contact(){

    ViewBag.Message = "Your contact page.";

 

    return View();}

注意,属性不表示容许读取联系人是谁——咱们逻辑移到一个单独的受权经理知道行动,资源和谁能够作哪一个操做在你的应用程序:

public class AuthorizationManager : ResourceAuthorizationManager{

    public override Task<bool> CheckAccessAsync(ResourceAuthorizationContext context)

    {

        switch (context.Resource.First().Value)

        {

            case "ContactDetails":

                return AuthorizeContactDetails(context);

            default:

                return Nok();

        }

    }

 

    private Task<bool> AuthorizeContactDetails(ResourceAuthorizationContext context)

    {

        switch (context.Action.First().Value)

        {

            case "Read":

                return Eval(context.Principal.HasClaim("role", "Geek"));

            case "Write":

                return Eval(context.Principal.HasClaim("role", "Operator"));

            default:

                return Nok();

        }

    }}

最后咱们受权管理器链接到OWIN管道Startup:

app.UseResourceAuthorization(new AuthorizationManager());

运行示例和步骤经过代码来熟悉流。

Ø 角色权限

然而,若是你选择使用[Authorize(Roles = "Foo,Bar")]要知道网站能够被扔进一个无限重定向循环当当前用户身份验证,但不属于其中的一个角色或用户进入AuthorizeMVC 5.2属性(验证)。 这是由于不良的结果Authorize属性将行动的结果是401年未受权用户身份验证,而不是一个的角色。 401结果触发重定向与IdentityServer进行身份验证,验证,而后将用户重定向回,而后重定向循环开始。 这种行为能够克服经过重写Authorize属性的HandleUnauthorizedRequest方法以下,而后使用自定义受权属性相反的MVC

// Customized authorization attribute:public class AuthAttribute : AuthorizeAttribute{

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)

    {

        if (filterContext.HttpContext.User.Identity.IsAuthenticated)

        {

            // 403 we know who you are, but you haven't been granted access

            filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.Forbidden);

        }

        else

        {

            // 401 who are you? go login and then try again

            filterContext.Result = new HttpUnauthorizedResult();

        }

    }}

// Usage:[Auth(Roles = "Geek")]public ActionResult About(){

    // ...}

Ø 更多的受权和处理拒绝访问场景

让咱们作更多受权经过添加一个新的操做方法Home控制器

[ResourceAuthorize("Write", "ContactDetails")]public ActionResult UpdateContact(){

    ViewBag.Message = "Update your contact details!";

 

    return View();}

当你试图调用,导航到采起行动/home/updatecontact您将看到一个URLforbidden错误页面。

 

事实上你会看到不一样的响应基于若是用户已经经过身份验证。 若是不是MVC将重定向到登陆页面,若是身份验证,您将看到禁止响应。 这是由设计(阅读更多在这里)

你能够经过检查处理被禁止的条件403状态码,咱们提供这样一个开箱即用的过滤:

[ResourceAuthorize("Write", "ContactDetails")][HandleForbidden]public ActionResult UpdateContact(){

    ViewBag.Message = "Update your contact details!";

 

    return View();}

HandleForbidden过滤器(固然也能够全球)将重定向到指定的视图时默认403获得了释放,咱们寻找一个视图Forbidden

 

您还可使用受权经理命令式地,给你更多的选择:

[HandleForbidden]public ActionResult UpdateContact(){

    if (!HttpContext.CheckAccess("Write", "ContactDetails", "some more data"))

    {

        // either 401 or 403 based on authentication state

        return this.AccessDenied();

    }

 

    ViewBag.Message = "Update your contact details!";

    return View();}

Ø 添加注销

添加注销很容易,只需添加一个新的操做调用Signout方法在武士刀的身份验证管理器:

public ActionResult Logout(){

    Request.GetOwinContext().Authentication.SignOut();

    return Redirect("/");}

这将启动所谓的往返endsessionIdentityServer端点。 这个端点将清晰的身份验证cookie和终止会话:

 

一般最安全的事情如今会简单地关闭浏览器窗口摆脱全部的会话数据。 一些应用程序虽然想给用户一个机会返回一个匿名用户。

这是可能的,但须要一些步骤,首先须要注册一个有效的URL注销手续完成后返回。 这样作是在客户端定义MVC应用程序(注意新PostLogoutRedirectUris设置):

new Client {

    Enabled = true,

    ClientName = "MVC Client",

    ClientId = "mvc",

    Flow = Flows.Implicit,

 

    RedirectUris = new List<string>

    {

        "https://localhost:44319/"

    },

    PostLogoutRedirectUris = new List<string>

    {

        "https://localhost:44319/"

    }}

下一个客户端必须证实其身份注销端点,以确保咱们重定向到正确的URL(而不是一些垃圾信息散布者/钓鱼页面)。 这是经过发送回最初的身份令牌,客户端身份验证过程当中收到了。 到目前为止,咱们已经丢弃这个令牌,如今是时候改变转换逻辑来保护它。

这是经过将这行代码添加到咱们的SecurityTokenValidated

// keep the id_token for logoutnid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));

最后一步,咱们必须把id_token当用户退出系统时,咱们让IdentityServer往返。 这也是使用通知OIDC中间件:

RedirectToIdentityProvider = async n =>

    {

        if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)

        {

            var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token").Value;

            n.ProtocolMessage.IdTokenHint = idTokenHint;

        }

    }

这些变化,IdentityServer会给用户一个连接返回到调用应用程序: 

Ø 添加谷歌身份验证

接下来,咱们想启用外部身份验证。 这是经过添加额外的武士刀认证中间件IdentityServer——在咱们的例子中,咱们将使用谷歌。

注册IdentityServer与谷歌

首先咱们须要注册IdentityServer在谷歌的开发者控制台。 这包括几个步骤。

首先导航到:

https://console.developers.google.com

l 建立一个新项目 

l 使Google + API 

l 赞成屏幕配置电子邮件地址和产品名称 

l 建立一个客户端应用程序

 

在您建立客户端应用程序,开发人员控制台将显示您客户id和一个客户的秘密。 咱们须要这两个值后,咱们配置谷歌中间件。

添加谷歌身份验证中间件

添加中间件经过安装如下方案:

install-package Microsoft.Owin.Security.Google

配置中间件

添加下面的方法Startup:

private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType){

    app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions

        {

            AuthenticationType = "Google",

            Caption = "Sign-in with Google",

            SignInAsAuthenticationType = signInAsType,

 

            ClientId = "...",

            ClientSecret = "..."

        });}

private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType){

    app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions

        {

            AuthenticationType = "Google",

            Caption = "Sign-in with Google",

            SignInAsAuthenticationType = signInAsType,

 

            ClientId = "...",

            ClientSecret = "..."

        });}

接下来咱们点IdentityServer选项类这个方法:

idsrvApp.UseIdentityServer(new IdentityServerOptions{

    SiteName = "Embedded IdentityServer",

    SigningCertificate = LoadCertificate(),

 

    Factory = InMemoryFactory.Create(

        users: Users.Get(),

        clients: Clients.Get(),

        scopes: Scopes.Get()),

 

    AuthenticationOptions = new Thinktecture.IdentityServer.Core.Configuration.AuthenticationOptions

    {

        IdentityProviders = ConfigureIdentityProviders

    }});

就是这样用户下次登陆时,会有一个登陆页面上的与谷歌登陆按钮:

 

请注意,role与谷歌声称丢失时登陆。 颇有意义,由于谷歌没有角色的概念。 作好准备,并不是全部的身份提供者将提供相同的声明类型。

v 第2部分-添加和调用Web API

在这部分咱们将添加一个Web API的解决方案。 API将由IdentityServer担保。 接下来咱们的MVC应用程序将调用API使用信任子系统和身份表明团的方法。

Ø 添加Web API项目

最简单的方法建立一个干净的API项目是经过添加一个空的web项目。

 

接下来,咱们将添加Web API和武士刀使用Nuget托管:

install-package Microsoft.Owin.Host.SystemWeb

install-package Microsoft.Aspnet.WebApi.Owin

Ø 添加一个测试控制器

下面的控制器将返回全部Claims回调用者——这将使咱们可以检查将发送到API的令牌。

[Route("identity")][Authorize]public class IdentityController : ApiController{

    public IHttpActionResult Get()

    {

        var user = User as ClaimsPrincipal;

        var claims = from c in user.Claims

                        select new

                        {

                            type = c.Type,

                            value = c.Value

                        };

 

        return Json(claims);

    }}

Ø 链接在启动Web API和安全

一如既往地Katana-based托管,发生在全部配置Startup:

public class Startup{

    public void Configuration(IAppBuilder app)

    {

        // web api configuration

        var config = new HttpConfiguration();

        config.MapHttpAttributeRoutes();

 

        app.UseWebApi(config);

    }}

另外咱们想确保咱们的API使用IdentityServer——须要两件事:

l 只接受IdentityServer发行的令牌

l 只接受令牌,发布了,咱们会给咱们的API——API的名称sampleApi(也称为scope)

完成,咱们添加一个Nuget:

install-package Thinktecture.IdentityServer3.AccessTokenValidation

. . 并使用它们Startup:

public class Startup{

    public void Configuration(IAppBuilder app)

    {

        app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions

        {

            Authority = "https://localhost:44319/identity",

            RequiredScopes = new[] { "sampleApi" }

        });

 

        // web api configuration

        var config = new HttpConfiguration();

        config.MapHttpAttributeRoutes();

 

        app.UseWebApi(config);

    }}

请注意IdentityServer问题标准JSON Web标记(JWT),你可使用普通的武士刀JWT中间件来验证它们。 咱们的中间件只是一个方便由于它能够自动配置自己使用IdentityServer发现文档(元数据)

Ø 注册在IdentityServer API

接下来咱们须要注册的API——这是经过扩展范围。 这一次咱们添加一个所谓的资源范围:

public static class Scopes{

    public static IEnumerable<Scope> Get()

    {

        var scopes = new List<Scope>

        {

            new Scope

            {

                Enabled = true,

                Name = "roles",

                Type = ScopeType.Identity,

                Claims = new List<ScopeClaim>

                {

                    new ScopeClaim("role")

                }

            },

            new Scope

            {

                Enabled = true,

                Name = "sampleApi",

                Description = "Access to a sample API",

                Type = ScopeType.Resource

            }

        };

 

        scopes.AddRange(StandardScopes.All);

 

        return scopes;

    }}

Ø 注册一个Web API客户端

接下来咱们将调用API。 你能够为使用客户端凭据(如服务账户)或经过受权用户的身份。 咱们将开始与客户凭证。

首先咱们须要注册一个新客户的MVC应用程序。出于安全缘由,IdentityServer只容许每一个客户一个流由于咱们现有MVC客户已经使用隐式流程,咱们须要建立一个新的客户服务的服务通讯。

public static class Clients{

    public static IEnumerable<Client> Get()

    {

        return new[]

        {

            new Client 

            {

                Enabled = true,

                ClientName = "MVC Client",

                ClientId = "mvc",

                Flow = Flows.Implicit,

 

                RedirectUris = new List<string>

                {

                    "https://localhost:44319/"

                }

            },

            new Client

            {

                Enabled = true,

                ClientName = "MVC Client (service communication)",

                ClientId = "mvc_service",

                ClientSecrets = new List<ClientSecret>

                {

                    new ClientSecret("secret".Sha256())

                },

 

                Flow = Flows.ClientCredentials

            }

        };

    }}

Ø 调用API

调用API包含两个部分:

l 请求令牌从IdentityServer API使用客户端证书

l 调用API使用访问令牌

简化与OAuth2令牌的交互端点,添加客户端包经过Nuget MVC项目:

install-package Thinktecture.IdentityModel.Client

在控制器中,添加新类CallApiController。 下面的代码片断的令牌的请求sampleApi

private async Task<TokenResponse> GetTokenAsync(){

    var client = new OAuth2Client(

        new Uri("https://localhost:44319/identity/connect/token"),

        "mvc_service",

        "secret");

 

    return await client.RequestClientCredentialsAsync("sampleApi");}

private async Task<TokenResponse> GetTokenAsync(){

    var client = new OAuth2Client(

        new Uri("https://localhost:44319/identity/connect/token"),

        "mvc_service",

        "secret");

 

    return await client.RequestClientCredentialsAsync("sampleApi");}

而如下代码片断调用咱们的身份端点使用请求的访问令牌:

private async Task<string> CallApi(string token){

    var client = new HttpClient();

    client.SetBearerToken(token);

 

    var json = await client.GetStringAsync("https://localhost:44321/identity");

    return JArray.Parse(json).ToString();}

把全部在一块儿,新添加的控制器调用服务并显示生成的声称在一个视图:

public class CallApiController : Controller{

    // GET: CallApi/ClientCredentials

    public async Task<ActionResult> ClientCredentials()

    {

        var response = await GetTokenAsync();

        var result = await CallApi(response.AccessToken);

 

        ViewBag.Json = result;

        return View("ShowApiResult");

    }

 

    // helpers omitted}

public class CallApiController : Controller{

    // GET: CallApi/ClientCredentials

    public async Task<ActionResult> ClientCredentials()

    {

        var response = await GetTokenAsync();

        var result = await CallApi(response.AccessToken);

 

        ViewBag.Json = result;

        return View("ShowApiResult");

    }

 

    // helpers omitted}

结果是这样的:

 

换句话说- API知道调用者:

l 发行人名称、观众和过时(使用的令牌验证中间件)

l 令牌的范围(范围验证使用的中间件)发布

l 客户机id

全部Claims的令牌将变成一个ClaimsPrincipal和经过.User控制器上的属性。

Ø 表明用户调用的API

接下来咱们要调用API使用用户的身份。 这是经过添加完成sampleApi范围的名单范围的OpenID链接中间件配置。 咱们还须要代表咱们想请求一个访问令牌经过改变反应类型:

Scope = "openid profile roles sampleApi",ResponseType = "id_token token"

尽快的响应类型token请求IdentityServer中止,包括Claims的身份令牌。 这是优化的目的,由于你如今有一个访问令牌,容许从用户信息检索的端点,同时保持身份令牌小。

访问端点并不难——用户信息UserInfoClient类可使它更简单。 除了咱们如今也将访问令牌存储在cookie,因此咱们可使用它当咱们想访问API表明用户:

SecurityTokenValidated = async n =>

    {

        var nid = new ClaimsIdentity(

            n.AuthenticationTicket.Identity.AuthenticationType,

            Constants.ClaimTypes.GivenName,

            Constants.ClaimTypes.Role);

 

        // get userinfo data

        var userInfoClient = new UserInfoClient(

            new Uri(n.Options.Authority + "/connect/userinfo"),

            n.ProtocolMessage.AccessToken);

 

        var userInfo = await userInfoClient.GetAsync();

        userInfo.Claims.ToList().ForEach(ui => nid.AddClaim(new Claim(ui.Item1, ui.Item2)));

 

        // keep the id_token for logout

        nid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));

 

        // add access token for sample API

        nid.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));

 

        // keep track of access token expiration

        nid.AddClaim(new Claim("expires_at", DateTimeOffset.Now.AddSeconds(int.Parse(n.ProtocolMessage.ExpiresIn)).ToString()));

 

        // add some other app specific claim

        nid.AddClaim(new Claim("app_specific", "some data"));

 

        n.AuthenticationTicket = new AuthenticationTicket(

            nid,

            n.AuthenticationTicket.Properties);

    }

另外一个选择是从新配置IdentityServer并设置的范围AlwaysIncludeInIdToken国旗声称力范围包含声称的身份令牌,我把它留给读者做为练习。

调用API

因为访问令牌如今存储在cookie,咱们能够简单地从Claims本金和用它来检索它调用服务:

// GET: CallApi/UserCredentialspublic async Task<ActionResult> UserCredentials(){

    var user = User as ClaimsPrincipal;

    var token = user.FindFirst("access_token").Value;

    var result = await CallApi(token);

 

    ViewBag.Json = result;

    return View("ShowApiResult");}

在结果页面上,您如今能够看到subClaims包括在内,这意味着API如今工做表明一个用户:

 

若是你如今添加范围要求rolesampleApi范围——用户的角色将被包括在访问令牌:

new Scope{

    Enabled = true,

    Name = "sampleApi",

    Description = "Access to a sample API",

    Type = ScopeType.Resource,

 

    Claims = new List<ScopeClaim>

    {

        new ScopeClaim("role")

    }}

        新 ScopeClaim(“角色”)

    }}

第四章配置

v 概述

IdentityServer3打包为中间件和使用典型的选项模式配置:

public void Configuration(IAppBuilder appBuilder){

    var options = new IdentityServerOptions

    {

        SigningCertificate = Certificate.Get(),

        Factory = factory,

    };

 

    appBuilder.UseIdentityServer(options);}

IdentityServerOptionsIdentityServer类包含全部配置。 一部分由发行人的简单属性名称或网站标题,您能够从任何你认为合适的来源(静态代码中,配置文件或数据库)。 另外一部分是所谓的服务工厂充当注册IdentityServer内部处理的某些方面。

托管在IIS和RAMMFAR

网页提供的文件做为嵌入式IdentityServer议会内部的资产。 当在IIS托管或IIS Express容许这些文件送达RAMMFAR(runAllManagedModulesForAllRequests)须要在web . config中启用:

<system.webServer>

  <modules runAllManagedModulesForAllRequests="true">

  </modules>

</system.webServer>

看到样品

v IdentityServer选项

IdentityServerOptions 的顶层容器IdentityServer的全部配置设置。

  • IssuerUri
    • 惟一的名称服务器实例,如https://myissuer.com。 默认为IdentityServer安装的基URL
  • SiteName
    • 网站的显示名称中使用标准的观点。
  • SigningCertificate
    • X。 509证书(和相应的私钥)签署安全令牌。
  • SecondarySigningCertificate
    • 二级证书,会发现文档。 可用于客户准备证书翻转。
  • RequireSsl
    • 代表若是SSL IdentityServer所需。 默认为true。
  • PublicOrigin
    • 默认状况下,IdentityServer使用主机、协议和端口从HTTP请求在建立连接。 这可能不是准确在反向代理或负载平衡状况。 你能够覆盖原点用于连接生成使用这个属性。
  • Endpoints
    • 容许启用或禁用特定的端点(默认状况下全部端点是启用)。
  • Factory(必需)
  • DataProtector
    • 自定义数据集的保护者。 在默认状况下使用武士刀主机数据保护。
  • AuthenticationOptions
  • PluginConfiguration
    • 容许添加协议插件如ws - federation支持。
  • CorsPolicy
  • CspOptions
  • ProtocolLogoutUrls
    • 配置回调url应该被称为在注销(主要用于协议插件)。
  • LoggingOptions
  • EventsOptions
  • EnableWelcomePage
    • 启用或禁用默认的欢迎页面。 默认为true。

v 服务工厂

IdentityServer3包含许多功能实现OpenIDOAuth2链接。 许多这些功能设计,这样他们就能够被取代。 这将是有用的场景缺省逻辑不匹配托管应用程序的需求,或者只是应用程序但愿提供一个彻底不一样的实现。 事实上,有些在IdentityServer3扩展点,须要提供的托管应用程序(如存储配置数据或验证的身份管理实现用户的凭证)

Thinktecture.IdentityServer.Core.Configuration.IdentityServerServiceFactory拥有全部这些构建块,必须提供在启动时使用IdentityServerOptions(在这里有关配置选项的更多信息)

扩展点分为三类。

v 强制性的

  • UserService
  • ScopeStore
    • 实现检索范围配置数据
  • ClientStore
    • 实现客户端配置数据的检索

InMemoryFactory容许设置一个服务工厂经过为用户提供内存存储,客户和范围(在这里)

v 强制性的生产场景(但默认内存中实现)

  • AuthorizationCodeStore
    • 实现存储和检索的受权码(接口)
  • TokenHandleStore
    • 实现存储和检索的处理令牌(供参考接口)
  • RefreshTokenStore
    • 实现存储和检索的刷新令牌(接口)
  • ConsentStore
    • 实现存储和检索的赞成决定(接口)
  • ViewService
    • 实现检索界面的资产。 默认使用嵌入的资产。 (接口)
  • TokenService
    • 实现建立身份和访问令牌(接口)
  • ClaimsProvider
    • 实现检索申请身份和访问令牌(接口)
  • TokenSigningService
    • 实现建立和签署安全令牌(接口)
  • CustomGrantValidator
    • 实现自定义的验证受权类型(接口)
  • CustomRequestValidator
    • 实现自定义额外的受权和验证令牌请求(接口)
  • RefreshTokenService
    • 实现建立和更新刷新令牌(接口)
  • ExternalClaimsFilter
    • 实现过滤和转换申请外部身份提供者(接口)
  • CustomTokenValidator
    • 实现自定义令牌的其余验证令牌验证端点(接口)
  • ConsentService
    • 实现逻辑赞成的决定(接口)
  • ClientPermissionsService
    • 实现了检索和撤销批准,引用和刷新令牌(接口)
  • EventService
    • 实现将事件转发给一些日志记录系统(如弹性搜索)(接口)
  • RedirectUriValidator
    • 实现验证重定向和注销后uri(接口)
  • LocalizationService
    • 实现显示的本地化字符串(接口)
  • ClientSecretValidator
    • 实现验证客户的秘密(接口)
  • CorsPolicyService
    • 实现了歌珥政策(接口)

v 可选(能够更换,但有默认的实现)

看到在这里有关注册定制服务的更多信息和存储的实现。

v 内存中的工厂

内存厂是一个简单的方法来获得一个测试/ dev版本IdentityServer启动并运行。

当你建立in-mem工厂你能够提供一个静态列表Client, ScopeInMemoryUser。 全部其余数据(e。 g赞成,刷新令牌,引用标记,代码等等)将只保存在内存中。 这只是适合测试和开发。

var factory = InMemoryFactory.Create(

    users:   Users.Get(),

    clients: Clients.Get(),

    scopes:  Scopes.Get());

var idsrvOptions = new IdentityServerOptions{

    Factory = factory,

    SigningCertificate = Cert.Load(),};

app.UseIdentityServer(idsrvOptions);

第五章客户

Client类模型OpenID链接或OAuth2客户机——例如一个本地应用程序中,web应用程序或者JS-based应用程序(连接)

  • Enabled
    • 指定是否启用客户机。 默认为true。
  • ClientId
    • 唯一的ID的客户端
  • ClientSecrets
    • 列表,客户须要一个秘密的秘密,只有相关的流
  • ClientName
    • 客户端显示名称(用于日志记录和赞成屏幕)
  • ClientUri
    • URI进一步信息客户端(赞成屏幕上使用)
  • LogoUri
    • URI端标志(赞成屏幕上使用)
  • RequireConsent
    • 指定是否须要赞成屏幕。 默认为true。
  • AllowRememberConsent
    • 指定用户能够选择存储是否赞成的决定。 默认为true。
  • Flow
    • 指定容许客户机(流AuthorizationCode, Implicit, Hybrid, ResourceOwner,ClientCredentials或Custom)。 默认为Implicit。
  • AllowClientCredentialsOnly
    • 获取或设置一个值指示是否容许该客户端请求令牌只使用客户端证书。 这是颇有用的,例如,你想要一个客户机可以使用一个以用户为中心流隐式和另外客户端凭证流。 默认值为false。 应该只用于机密客户(如不隐式)。
  • RedirectUris
    • 指定容许的uri返回标记或受权代码
  • PostLogoutRedirectUris
    • 注销后重定向到指定容许的uri
  • ScopeRestrictions
    • 指定范围,容许客户端请求。 若是空,客户端能够请求做用域。 默认为空集合。
  • IdentityTokenLifetime
    • 一辈子的身份令牌在几秒钟内(默认为300秒/ 5分钟)
  • AccessTokenLifetime
    • 一辈子的访问令牌在几秒钟内(默认为3600秒/ 1小时)
  • AuthorizationCodeLifetime
    • 一辈子的受权代码秒(默认为300秒/ 5分钟)
  • AbsoluteRefreshTokenLifetime
    • 一辈子最大的刷新令牌在几秒钟内。 默认为2592000秒/ 30天
  • SlidingRefreshTokenLifetime
    • 滑动的一辈子秒刷新令牌。 默认为1296000秒/ 15天
  • RefreshTokenUsage
    • ReUse:刷新令牌处理刷新令牌时将保持不变
    • OneTime:刷新令牌处理刷新令牌时将被更新
  • RefreshTokenExpiration
    • Absolute:刷新令牌将到期在一个固定的时间点(AbsoluteRefreshTokenLifetime指定的)
    • Sliding:当刷新令牌,将再次刷新令牌的生命周期(经过SlidingRefreshTokenLifetime中指定的数量)。 一辈子不会超过AbsoluteRefreshTokenLifetime。
  • AccessTokenType
    • 指定是否访问令牌是一个参考标记或自包含JWT令牌(默认Jwt)。
  • EnableLocalLogin
    • 指定若是这个客户端可使用本地账户,或外部国内流离失所者。 默认为true。
  • IdentityProviderRestrictions
    • 指定与该客户端可使用外部的国内流离失所者(若是容许列表为空全部国内流离失所者)。 默认为空。
  • IncludeJwtId
    • 指定JWT访问令牌是否应该有一个嵌入式唯一的ID(经过jtiClaims)。
  • Claims
    • 容许设置申请客户端(将包括在访问令牌)。
  • AlwaysSendClientClaims
    • 若是设置,客户声称将发送每流。 若是没有,只有客户端凭证流(默认false)
  • PrefixClientClaims
    • 若是设置,全部客户端将前缀client_确保他们不意外碰撞与用户要求。 默认是true。
  • CustomGrantTypeRestrictions
    • 列表容许自定义受权类型被设置为当流Custom。 若是列表为空,全部自定义受权类型是容许的。 默认为空。

除了有不少设置控制刷新令牌——看到的行为在这里

Ø 例如:为隐式流配置客户端

var client = new Client{

    ClientName = "JS Client",

    Enabled = true,

 

    ClientId = "implicitclient",

    Flow = Flows.Implicit,

 

    RequireConsent = true,

    AllowRememberConsent = true,

 

    RedirectUris = new List<string>

    {

        "https://myapp/callback.html"

    },

 

    PostLogoutRedirectUris = new List<string>

    {

        "http://localhost:23453/index.html"

    }}

var client = new Client{

    ClientName = "JS Client",

    Enabled = true,

 

    ClientId = "implicitclient",

    Flow = Flows.Implicit,

 

    RequireConsent = true,

    AllowRememberConsent = true,

 

    RedirectUris = new List<string>

    {

        "https://myapp/callback.html"

    },

 

    PostLogoutRedirectUris = new List<string>

    {

        "http://localhost:23453/index.html"

    }}

Ø 例如:为资源全部者流配置客户端

var client = new Client{

    ClientName = "Legacy Client",

    Enabled = true,

 

    ClientId = "legacy",

    ClientSecrets = new List<ClientSecret>

    {

        new ClientSecret("4C701024-0770-4794-B93D-52B5EB6487A0".Sha256())

    },

 

    Flow = Flows.ResourceOwner,

 

    AbsoluteRefreshTokenLifetime = 86400,

    SlidingRefreshTokenLifetime = 43200,

    RefreshTokenUsage = TokenUsage.OneTimeOnly,

    RefreshTokenExpiration = TokenExpiration.Sliding}

v 范围和Claims

Ø Thinktecture.IdentityServer.Core.Models.Scope类的模型OpenID链接或OAuth2范围。

  • Enabled
    • 代表若是启用了范围,能够请求。 默认为true。
  • Name
    • 范围的名称。 这是客户机将使用请求的值范围。
  • DisplayName
    • 为赞成屏幕显示名称。
  • Description
    • 屏幕描述赞成。
  • Required
    • 指定用户是否能够取消屏幕上赞成的范围。 默认为false。
  • Emphasize
    • 指定是否赞成屏幕将会强调这个范围。 使用此设置敏感或重要的范围。 默认为false。
  • Type
    • 要么Identity(OpenID链接相关)或Resource(OAuth2参考资料)。 默认为Resource。
  • Claims
    • 列表用户声称应该归入到身份(身份范围)或访问令牌(资源范围)。
  • IncludeAllClaimsForUser
    • 若是启用,全部的用户将被包含在令牌。 默认为false。
  • ClaimsRule
    • 肯定哪些赔偿规则应该被包括在令牌(这是特定于实现的)
  • ShowInDiscoveryDocument
    • 指定是否发现文档中显示这个范围。 默认为true。

还能够指定范围声称进入相应的令牌-ScopeClaim类具备如下属性:

  • Name
    • Claims的名称
  • Description
    • 要求的描述
  • AlwaysIncludeInIdToken
    • 指定是否这种说法应该出如今身份令牌(即便一个访问令牌请求)。 只适用于标识范围。 默认为false。

的例子role身份范围:

var roleScope = new Scope{

    Name = "roles",

    DisplayName = "Roles",

    Description = "Your organizational roles",

    Type = ScopeType.Identity,

 

    Claims = new List<ScopeClaim>

    {

        new ScopeClaim(Constants.ClaimTypes.Role, alwaysInclude: true)

    }};

“AlwaysIncludeInIdentityToken”属性指定一个特定的应该是身份标识的一部分,即便用户信息的访问令牌端点的请求。

例子的范围IdentityManager API:

var idMgrScope = new Scope{

    Name = "idmgr",

    DisplayName = "Thinktecture IdentityManager",

    Type = ScopeType.Resource,

    Emphasize = true,

 

    Claims = new List<ScopeClaim>

    {

        new ScopeClaim(Constants.ClaimTypes.Name),

        new ScopeClaim(Constants.ClaimTypes.Role)

    }};

v 身份验证选项

这个话题能够找到的样本在这里

AuthenticationOptions是一个属性的吗IdentityServerOptions自定义登陆和注销的观点和行为。

  • EnableLocalLogin
    • 代表若是IdentityServer将容许用户与本地账户进行身份验证。 禁用此设置不会显示用户名/密码表单登陆页面。 这也将禁用资源全部者密码流。 默认为true。
  • EnableLoginHint
    • 指示是否login_hint参数是用于预填充用户名字段。 默认为true。
  • LoginPageLinks
    • 的列表LoginPageLink对象。 这些容许login视图提供用户自定义到其余web页面的连接,他们可能须要访问以前登陆(如注册页面,或密码重置页面)。
    • LoginPageLink包含:
      • Text:出如今连接的文本。
      • Href:的URLhref的连接。
    • 自定义web页面所表明的LoginPageLink将提供的托管应用程序。 一旦执行它的任务就能够恢复登陆工做流将用户重定向回登陆视图。
    • 当用户遵循的一个LoginPageLink年代,signin查询字符串参数是传递到页面。 这个参数应该做为一个回响signin查询字符串参数到登陆页面,当用户想恢复其登陆。 login视图位于路径”~ / login”相对于IdentityServer的应用基础。
  • RememberLastUsername
    • 代表IdentityServer是否还记得过去的用户名进入登陆页面。 默认为false。
  • IdentityProviders
    • 容许配置额外的身份提供者——看到在这里
  • CookieOptions
    • CookieOptions对象配置如何由IdentityServer饼干。
    • CookieOptions这些属性:
      • Prefix:容许在饼干上设置一个前缀,以免潜在的冲突与其余饼干使用相同的名称。 默认状况下不使用前缀。
      • ExpireTimeSpan:验证cookie的过时时间。 默认为10个小时。
      • IsPersistent:代表身份验证cookie是否被标记为持久性。 默认为false。
      • SlidingExpiration:表示若是身份验证cookie是滑动,这意味着它自动更新用户是活跃的。 默认为false。
      • Path:设置cookie的道路。 默认为IdentityServer在托管应用程序的基本路径。
      • AllowRememberMe:表示“记住我”选项是否呈现给用户的登陆页面。 若是选择这个选项将发行持续验证cookie。 默认为true。
        • 若是这个设置是使用用户的决定(是或否)将覆盖IsPersistent设置。 换句话说,若是两个IsPersistent和AllowRememberMe启用用户决定他们不记得登陆,而后不会发行持久化cookie。
        • RememberMeDuration:持久化cookie签发时间登陆页面上的“记住我”选项。 默认为30天。
        • SecureMode:获取或设置模式发布安全标志的饼干。 默认为SameAsRequest。
  • EnableSignOutPrompt
    • 代表通过IdentityServer是否会显示一个确认页。 当一个客户端发起一个捲,默认状况下IdentityServer将要求用户确认。 这是一个缓解技术对垃圾邮件“注销”。 默认为true。
  • EnablePostSignOutAutoRedirect
    • 获取或设置一个值,指出是否IdentityServer自动重定向回验证post_logout_redirect_uri传递到signout端点。 默认为false。
  • PostSignOutAutoRedirectDelay
    • 获取或设置重定向到一个以前延迟(以秒为单位)post_logout_redirect_uri。 默认为0。
  • SignInMessageThreshold
    • 获取或设置限制以后,老signin消息(饼干)清除。 默认为5。
  • InvalidSignInRedirectUrl
    • 获取或设置无效登陆重定向URL。 若是用户到达登陆页面没有一个有效的登陆请求,而后他们将被重定向到该URL。 URL必须绝对或相对URL(从“~ /”)。

v 身份提供者

IdentityServer支持使用外部身份验证提供者。 外部身份验证机制必须封装在一个武士刀认证中间件。

武士刀自己附带的中间件为谷歌、FacebookTwitter、微软帐户,ws - federationOpenID链接,但也有社区开发中间件)(包括雅虎、LinkedInSAML2p)。 看到这里的选项列表

为外部提供者配置中间件,添加一个方法接受一个项目IAppBuilder和一个string

public static void ConfigureIdentityProviders(IAppBuilder app, string signInAsType){

    var google = new GoogleOAuth2AuthenticationOptions

    {

        AuthenticationType = "Google",

        Caption = "Google",

        SignInAsAuthenticationType = signInAsType,

        ClientId = "...",

        ClientSecret = "..."

    };

    app.UseGoogleAuthentication(google);

 

    var fb = new FacebookAuthenticationOptions

    {

        AuthenticationType = "Facebook",

        Caption = "Facebook",

        SignInAsAuthenticationType = signInAsType,

        AppId = "...",

        AppSecret = "..."

    };

    app.UseFacebookAuthentication(fb);

 

    var twitter = new TwitterAuthenticationOptions

    {

        AuthenticationType = "Twitter",

        Caption = "Twitter",

        SignInAsAuthenticationType = signInAsType,

        ConsumerKey = "...",

        ConsumerSecret = "..."

    };

    app.UseTwitterAuthentication(twitter);}

笔记

AuthenticationType必须是一个独特的价值来肯定外部身份提供商。 这个值也将用于idp在生成的令牌。 并且相同的值能够用着身份提供者在使用受权/身份验证请求acr_values参数(的更多信息)。 这个值也用来限制容许在身份提供者Client配置。

Caption登陆页面上指定的标签按钮身份提供商。 若是Caption是一个空字符串,身份提供者在登陆页面将不会显示。 但仍然能够经过登陆提示。

SignInAsAuthenticationType必须设置为咱们传递的价值经过吗signInAsType参数

指定配置方法IdentityProviders财产的AuthenticationOptions:

var idsrvOptions = new IdentityServerOptions{

    SiteName = "IdentityServer3",

    Factory = factory,

    SigningCertificate = Cert.Load(),

 

    AuthenticationOptions = new AuthenticationOptions 

    {

        IdentityProviders = ConfigureIdentityProviders

    }};

app.UseIdentityServer(idsrvOptions);

v 添加ws - federation身份提供者

基于ws - federation身份提供者能够以相同的方式添加如上所示。

向后兼容性缘由,ws - federation中间件听全部传入请求和检查传入令牌的帖子。 这不是一个问题,若是你只有一个ws - federation中间件配置,可是若是你有不止一个,你须要设置一个显式的和独特的CallbackPath属性相匹配的回复URL配置在国内流离失所者。 请注意,CallbackPath必须相对于根目录,而不是相对于身份服务器模块路径。 例如,若是外部提供者配置为post身份验证令牌http://mydomain.com/SubFolder/IdSrv/MyExternalProvider而后CallbackPath应该设置为/SubFolder/IdSrv/MyExternalProvider

var adfs = new WsFederationAuthenticationOptions{

    AuthenticationType = "adfs",

    Caption = "ADFS",

    SignInAsAuthenticationType = signInAsType,  MetadataAddress = "https://adfs.leastprivilege.vm/federationmetadata/2007-06/federationmetadata.xml",

 

    Wtrealm = "urn:idsrv3"};app.UseWsFederationAuthentication(adfs);

v HSTS

HTTP严格的运输安全(hst)是网络安全的一个重要方面。 IdentityServer3提供了一个配置选项包括hst头在它全部的HTTP响应。 要启用,使用UseHsts扩展方法IAppBuilder在你OWIN配置:

public void Configuration(IAppBuilder app){

    app.UseHsts();

 

    // ...}

若是你想设置过时(max-age),而后UseHsts过载,接受吗int的天数或者一个TimeSpan为一个自定义的持续时间。 的值0TimeSpan.Zero能够用来清洗hst浏览器缓存。 默认过时30天。

v CORS

许多端点IdentityServer将经过Ajax调用从JavaScript访问。 鉴于IdentityServer极可能比这些客户托管在一个不一样的起源,这意味着跨源资源共享(歌珥)将是一个问题。

v 歌珥政策服务

IdentityServer3容许托管应用程序来实现ICorsPolicyService肯定歌珥政策。 该服务注册的IdentityServerServiceFactory

单一方法ICorsPolicyService:

  • Task<bool> IsOriginAllowedAsync(string origin)
    • 返回true若是origin是容许的,false不然。

你能够实现一个自定义的实如今任何你认为合适的方式来肯定若是调用起源是被容许的。

Ø 提供实现

有两种实现提供从IdentityServer核心:

  • DefaultCorsPolicyService
    • 这个实现可使用若是容许起源的列表容许是固定的和已知的在应用程序开始。 的AllowedOrigins属性的集合,能够confgured的起源,应该容许列表。
    • 还有一个AllowAll属性能够设置true容许全部的起源。
  • InMemoryCorsPolicyService
    • 这个实现接受做为构造函数参数列表Client对象。 歌珥的起源能够经过配置AllowedCorsOrigins财产的Client对象。

有一个最后的实现提供了从IdentityServer3.EntityFramework:

  • ClientConfigurationCorsPolicyService
    • 这个实现了其列表容许的起源AllowedCorsOrigins财产的Client对象存储在数据库中。

v 弃用:CorsPolicy

在版本1.0.0 IdentityServerCorsPolicy是惟一的方法来支持歌珥和如今已经弃用上述歌珥政策服务。 下面的文档维护,由于1.0.0特性仍然支持,但在将来的版本将被删除。

Ø CorsPolicy

IdentityServer3容许托管应用程序配置CorsPolicyIdentityServerOptions控制容许哪些起源。

AllowedOrigins

CorsPolicy有两种方法能够指定容许哪些起源。 第一个是AllowedOrigins主机名称的集合。 这是有用的,若是在应用程序启动时间的起源是已知的(硬编码或可能从数据库加载)

var idsvrOptions = new IdentityServerOptions();

idsrvOptions.CorsPolicy.AllowedOrigins.Add("http://myclient.com");

idsrvOptions.CorsPolicy.AllowedOrigins.Add("http://myotherclient.org);

PolicyCallback

第二个方法CorsPolicy容许托管应用程序显示容许哪些起源是PolicyCallback表明这是一个Func<string, Task<bool>>。 在运行时调用该委托歌珥请求时被请求IdentityServer并经过原点。 一个返回bool的价值true代表,原点是被容许的。 这是有用的,若是常常更改容许起源列表或者足够大,这样一个数据库查找者优先。

var idsvrOptions = new IdentityServerOptions();

idsrvOptions.CorsPolicy.PolicyCallback = async origin =>{

    return await SomeDatabaseCallToCheckIfOriginIsAllowed(origin);};

CorsPolicy.AllowAll

为了方便有一个静态属性CorsPolicy.AllowAll这将容许全部的起源。 这是有用的调试或发展。

var idsvrOptions = new IdentityServerOptions {

    CorsPolicy = CorsPolicy.AllowAll};

v 日志记录

IdentityServer产生普遍的日志输出。 日志记录机制,水槽是由经过设定一个托管应用程序LogProvider(例如,在你的startup):

LogProvider。SetCurrentLogProvider(新 DiagnosticsTraceLogProvider());

如下供应商的支持:

l System.Diagnostics。 跟踪(DiagnosticsTraceLogProvider)

l TraceSource(TraceSourceLogProvider)

l NLog(NLogLogProvider)

l 企业图书馆(EntLibLogProvider)

l SeriLog(SerilogLogProvider)

l Log4Net(Log4NetLogProvider)

l 放大镜(LoupeLogProvider)

您能够建立额外的提供者的推导LogProvider

v 配置诊断

的LoggingOptions类具备如下设置:

  • EnableWebApiDiagnostics
    • 若是启用,Web API内部诊断日志记录将被转发到日志提供者
  • WebApiDiagnosticsIsVerbose
    • 若是启用,Web API诊断日志记录将被设置为详细
  • EnableHttpLogging
    • 若是启用,HTTP请求和响应将被记录
  • IncludeSensitiveDataInLogs
    • 若是启用,标准的日志可能包含敏感数据,如PII数据

警告 EnableHttpLogging可能的冲突与其余框架加载到相同的web应用程序(它确定与MVC)。 您不能使用HTTP记录在这种状况下。

v 配置系统 诊断提供者

如下代码片断添加到您的配置文件将全部日志消息到一个简单的文本文件。 咱们使用Baretail查看日志文件。

注意:若是你使用这种方法你须要确保帐户运行应用程序池包含日志文件的目录有写访问权限。 若是你不指定一个路径,这将是应用程序目录,不建议生产场景。 生产记录到一个文件外应用程序目录。

<system.diagnostics>

  <trace autoflush="true"

         indentsize="4">

    <listeners>

      <add name="myListener"

           type="System.Diagnostics.TextWriterTraceListener"

           initializeData="Trace.log" />

      <remove name="Default" />

    </listeners>

  </trace></system.diagnostics>

 

 

 

v 配置TraceSource提供者

如下代码片断添加到您的配置文件。 您可使用服务跟踪查看器的工具。 净SDK检查跟踪文件。

<sources>

  <source name="Thinktecture.IdentityServer"

          switchValue="Information, ActivityTracing">

    <listeners>

      <add name="xml"

            type="System.Diagnostics.XmlWriterTraceListener"

            initializeData= "trace.svclog" />

    </listeners>

  </source></sources>

v 插装本身的代码

您还可使用日志系统在您本身的代码的可扩展性。

添加一个静态ILog实例类

private readonly static ILog Logger = LogProvider.GetCurrentClassLogger();

使用日志记录器记录你的消息

Logger.Debug("Getting claims for identity token");

v 事件

IdentityServer在运行时引起了一系列的事件,:

l 成功/失败身份验证(资源全部者流,pre、片面、本地和外部)

l 令牌发出(身份、访问刷新令牌)

l 令牌处理相关事件(受权代码刷新令牌发出/赎回/刷新)

l 许可撤销

l 端点成功/失败

l 过时无效/没有签名证书

l 未处理的异常和内部错误

l CSP错误报告的浏览器。 看到CSP为更多的信息。

默认状况下这些事件转发到日志提供者——配置 一个定制的事件服务能够处理或以任何方式提出适合环境。

v 配置事件

的EventsOptions类具备如下设置(默认false):

  • RaiseSuccessEvents
    • 如刷新刷新令牌或身份验证成功
  • RaiseFailureEvents
    • 如身份验证失败,受权代码救赎失败
  • RaiseErrorEvents
    • 如未处理的异常
  • RaiseInformationEvents
    • 如令牌有效发行或证书

第六章端点

v 受权/身份验证端点

受权端点能够用来请求访问令牌或受权码(隐式和受权代码流)。 你可使用一个web浏览器或web视图开始这个过程。

Ø 支持参数

看到规范

  • client_id(必需)
    • 客户机的标识符
  • scope(必需)
    • 一个或多个注册范围
  • redirect_uri(必需)
    • 必须精确匹配的一个容许重定向uri的客户吗
  • response_type(必需)
    • code请求一个受权代码
    • token请求一个访问令牌(只容许资源范围)
    • id_token token请求一个身份令牌和一个访问令牌(包括资源和身份容许范围)
  • response_mode(可选)
    • form_post发送令牌响应做为后一种形式,而不是一个片断编码的重定向
  • state(推荐)
    • idsrv将回声状态值标记的回应,这是对于关联请求和响应
  • nonce(所需的身份令牌使用隐式流)
    • idsrv将回声的nonce价值身份令牌,这是关联的令牌请求)
  • prompt(可选)
    • none没有用户界面将显示在请求。 若是这是不可能的(例如,由于用户必须登陆或赞成)将返回一个错误
    • login登陆界面将显示,即便用户拥有一个有效的会话
  • login_hint(可选)
    • 可用于预填写登陆页面上的用户名字段
  • max_age(可选)
    • 若是用户的登陆会话超过最大年龄(以秒为单位),登陆界面将显示
  • acr_values(可选)
    • 容许经过额外的身份验证相关信息用户服务——还有价值观具备特殊的意义:
      • idp:name_of_idp绕过登陆屏幕/家庭领域,并将用户直接转发给所选身份提供商每客户端配置(若是容许)
      • tenant:name_of_tenant能够用来传递一个租户名称的用户服务

Ø 例子

可读性(URL编码删除)

GET /connect/authorize?client_id=client1&scope=openid email api1&response_type=id_token token&redirect_uri=https://myapp/callback&state=abc&nonce=xyz

v 令牌端点

令牌端点能够用于以编程方式请求或刷新令牌(资源全部者凭证流密码,受权代码流,客户端凭证流和自定义受权类型)。

Ø 支持参数

看到规范

  • grant_type(必需)
    • authorization_code, client_credentials, password, refresh_token或自定义
  • scope(所需的全部受权类型除了refresh_token和代码)
  • redirect_uri(所需代码授予类型)
  • code(所需代码授予)
  • username格兰特(所需的密码类型)
  • password(密码grant_type所需)
  • acr_values(容许密码受权类型将额外的信息传递给用户的服务)
    • 有值和特殊的意义:
      • idp:name_of_idp绕过登陆屏幕/家庭领域,并将用户直接转发给所选身份提供商每客户端配置(若是容许)
      • tenant:name_of_tenant可使用额外的信息传递给用户服务
  • refresh_token(须要刷新令牌受权)
  • client_id(后的身体,或做为一个基自己份验证头)
  • client_secret(后的身体,或做为一个基自己份验证头)

Ø 身份验证

全部请求令牌端点必须通过身份验证——要么经过基自己份验证经过客户机id和秘密 或添加client_idclient_secret字段的身体。

当提供client_idclient_secretAuthorization头预计:

l client_id:client_secret

l Base64编码的

var clientId = "...";

var clientSecret = "...";

var encoding = Encoding.UTF8;

var credentials = string.Format("{0}:{1}", clientId, clientSecret);

var headerValue = Convert.ToBase64String(encoding.GetBytes(credentials));

Ø 例子

(Form-encoding删除和添加换行符是为了增长可读性)

POST /connect/token

Authorization: Basic abcxyz

 

grant_type=authorization_code&

code=hdh922&

redirect_uri=https://myapp.com/callback

v 用户信息端点

UserInfo端点能够用来获取身份信息主题。 它须要一个有效的访问令牌至少openid的范围。

看到规范

Ø 例子

 

 

GET /connect/userinfo

Authorization: Bearer <access_token>

HTTP/1.1 200 OK

Content-Type: application/json

 

{

   "sub": "248289761001",

   "name": "Bob Smith",

   "given_name": "Bob",

   "family_name": "Smith",

   "role": [

       "user",

       "admin"

   ]

}

v 发现端点

发现端点能够用来检索关于IdentityServer——它返回元数据信息,如发行人名称、关键材料,支持范围等。

看到规范

Ø 例子

GET /.well-known/openid-configuration

v 注销端点

重定向到注销端点扫清了身份验证会话和饼干。

您能够经过如下的端点可选参数:

  • id_token_hint
    • 客户机的id_token期间得到认证。 这容许绕过注销确认屏幕以及提供一篇注销重定向URL
  • post_logout_redirect_uri
    • 一个URI,IdentityServer能够重定向到后注销(默认状况下显示一个连接)。 URI必须容许注销后URI列表中的客户端。

/connect/endsession?id_token_hint=...&post_logout_redirect_uri=https://myapp.com

看到AuthenticationOptions

v 令牌撤销

这个端点容许撤销访问令牌(仅参考标记)和刷新令牌。 它实现了令牌撤销规范(RFC 7009)

支持参数:

  • token(必需)
    • 令牌撤销
  • token_type_hint
    • 要么access_token或refresh_token

使用一个支持的请求必须通过身份验证的客户端身份验证方法。

例子:

POST /connect/revocation HTTP/1.1

Host: server.example.com

Content-Type: application/x-www-form-urlencoded

Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW

 

token=45ghiukldjahdnhzdauz&token_type_hint=refresh_token

v 访问令牌验证端点

访问令牌验证端点能够用来验证参考标记。 它也能够用来验证独立JWT若是消费者没有支持适当的JWT或加密库。

Ø 例子

GET /connect/accesstokenvalidation?token=<token>

一个成功的响应将返回一个状态码200和相关申请令牌。 一次不成功的响应将返回一个400错误消息。

还能够经过一个范围,预计将在令牌:

GET /connect/accesstokenvalidation?token=<token>&expectedScope=calendar

v 身份令牌验证端点

身份令牌验证端点能够用来验证身份令牌。 这是有用的为客户,没法得到适当的JWT或加密库(例如JavaScript)

Ø 例子

GET /connect/identitytokenvalidation?token=<token>&client_id=<expected_client_id>

一个成功的响应将返回一个状态码200和相关申请令牌。 一次不成功的响应将返回一个400错误消息。

{

  "nonce": "nonce",

  "iat": "1413203421",

  "sub": "88421113",

  "amr": "password",

  "auth_time": "1413203419",

  "idp": "idsrv",

  "iss": "https://idsrv3.com",

  "aud": "implicitclient",

  "exp": "1413203781",

  "nbf": "1413203421"

}

v CSP端点

CSP容许端点配置报告。 IdentityServer CSP的错误记录浏览器提供一个端点报告。 这些CSP错误将提升事件在事件系统。

CSP报告特性能够经过设置禁用EnableCspReportEndpoint财产falseEndpointOptions的一个属性是什么IdentityServerOptions

第七章先进的

v 刷新令牌

l 刷新令牌支持如下流:受权代码,混合动力和资源全部者凭证流密码。

l 客户须要容许请求offline_access范围刷新令牌。

Ø 设置在客户端类

  • RefreshTokenUsage
    • 重用:刷新令牌处理刷新令牌时将保持不变
    • 前:刷新令牌处理刷新令牌时将被更新
  • RefreshTokenExpiration
    • 绝对:刷新令牌将到期在一个固定的时间点(AbsoluteRefreshTokenLifetime指定的)
    • 滑动:刷新令牌时,将再次刷新令牌的生命周期(经过SlidingRefreshTokenLifetime中指定的数量)。 绝对不会超过生命一辈子。
  • AbsoluteRefreshTokenLifetime
    • 一辈子最大的刷新令牌在几秒钟内。 默认为2592000秒/ 30天
  • SlidingRefreshTokenLifetime
    • 滑动的一辈子秒刷新令牌。 默认为1296000秒/ 15天

Ø 使用

l 请求offline_access范围(经过代码或资源全部者流)

l 使用刷新令牌refresh_token格兰特

Ø 样品

l 客户端样本既有资源全部者代码流

 

v 定制服务

IdentityServer3提供了许多扩展点用于存储数据,验证逻辑和通用功能 支持IdentityServer所需的操做做为一个令牌服务。 这些不一样的扩展点统称为服务

看到在这里服务的完整列表。

v 强制性的服务

三是强制性的,必须配置的服务实现者,他们是: 

l 用户服务(IUserService) 

l 客户端存储(IClientStore) 

l 存储(范围IScopeStore) 

咱们提供一个简单的内存版本的这三个服务以及支持经过回购或社区项目相关的数据存储。 看到在这里为更多的细节。

v 注册定制服务

你能够取代全部服务和注册额外定义的。 这是封装的Registration类。 一个Registration表明一种IdentityServer得到您的服务的一个实例。

根据您的服务的设计您可能想要对每一个请求一个新实例,使用单例或者你可能须要特殊的实例化逻辑每次实例是必要的。 为了适应这些不一样的可能性,Registration类提供了许多不一样的构造函数来注册服务:

  • new Registration<T>(Type yourImplementation)
    • 寄存器yourImplementation当类实现T接口。
  • new Registration<T, Impl>()
    • 寄存器Impl当类实现T接口。 这个API是一个简单方便的接受的前面Type参数。
  • new Registration<T>(T singleton)
    • 注册singleton做为一个单例实现传递的实例T接口。
  • new Registration<T>(Func<IDependencyResolver, T> factory)
    • 注册一个回调函数,将调用返回的实现T接口。

var factory = new IdentityServerServiceFactory();factory.UserService = new Registration<IUserService, MyCustomUserService>();

看到这个页面依赖注入(DI)页面了解更多细节。

Ø 服务清理

在全部状况下,除了单,若是您的服务实现IDisposable,而后Dispose

第八章依赖注入

这个话题能够找到的样本在这里

IdentityServer3已经为各类服务扩展点。 默认的实现这些服务被设计为与其余IdentityServer移动部件 ,所以咱们使用依赖注入一切链接起来。

v 注入IdentityServer服务

默认提供的服务能够取代IdentityServer托管应用程序(若是须要的话)。 自定义实现也可使用依赖项注入和IdentityServer类型甚至定制类型注射。 这仅仅是支持自定义服务和商店注册使用Registration

定制服务接受IdentityServer定义的类型,只是代表这些依赖项做为构造函数参数。 当IdentityServer实例化你的注册类型构造函数的参数将被自动解决。 例如:

public class MyCustomTokenSigningService: ITokenSigningService{

    private readonly IdentityServerOptions _options;

 

    public MyCustomTokenSigningService(IdentityServerOptions options)

    {

        _options = options;

    }

 

    public Task<string> SignTokenAsync(Token token)

    {

        // ...

    }}

public class MyCustomTokenSigningService: ITokenSigningService{

    private readonly IdentityServerOptions _options;

 

    public MyCustomTokenSigningService(IdentityServerOptions options)

    {

        _options = options;

    }

 

    public Task<string> SignTokenAsync(Token token)

    {

        // ...

    }}

这是注册为这样:

var factory = new IdentityServerServiceFactory();factory.TokenSigningService = new Registration<ITokenSigningService>(typeof(MyCustomTokenSigningService));

或者用这个语法:

var factory = new IdentityServerServiceFactory();factory.TokenSigningService = new Registration<ITokenSigningService, MyCustomTokenSigningService>();

v 注入定制服务

定制服务也可能依赖于你本身的类型。 这些也能够注入只要他们已经配置了IdentityServer的依赖注入系统。 这是经过添加新注册使用IdentityServerServiceFactoryRegister()方法。 例如,若是你须要定制日志记录器服务:

public interface ICustomLogger{

    void Log(string message);}

public class DebugLogger : ICustomLogger{

    public void Log(string message)

    {

        Debug.WriteLine(message);

    }}

public class MyCustomTokenSigningService: ITokenSigningService{

    private readonly IdentityServerOptions _options;

    private readonly ICustomLogger _logger;

 

    public MyCustomTokenSigningService(IdentityServerOptions options, ICustomLogger logger)

    {

        _options = options;

        _logger = logger;

    }

 

    public Task<string> SignTokenAsync(Token token)

    {

        // ...

    }}

而后它将被登记为这样:

var factory = new IdentityServerServiceFactory();factory.TokenSigningService = new Registration<ITokenSigningService, MyCustomTokenSigningService>();factory.Register(new Registration<ICustomLogger, MyCustomDebugLogger>());

Ø 没有一个接口定制服务

在上面的例子中注入类型是ICustomLoggerimpelemntationMyCustomDebugLogger。 若是没有设计定制服务接口实现单独的合同,而后注册的具体类型自己能够被注入。

例如,若是MyCustomTokenSigningService的构造函数不接受记录器的接口,所以:

public class MyCustomTokenSigningService: ITokenSigningService{

    public MyCustomTokenSigningService(IdentityServerOptions options, MyCustomDebugLogger logger)

    {

        _options = options;

        _logger = logger;

    }

 

    // ...}

而后registraion可配置是这样的:

var factory = new IdentityServerServiceFactory();

factory.TokenSigningService = new Registration<ITokenSigningService,

 MyCustomTokenSigningService>();

factory.Register(new Registration<MyCustomDebugLogger>());

简而言之,这种类型的注册意味着MyCustomDebugLogger具体类型是被注入依赖的类型。

v 建立自定义

若是你的服务是必要的人工构造(如您须要传递特定参数的构造函数),而后您可使用Registration,容许一个工厂要使用回调。 这Registration这个签名:

new Registration<T>(Func<IDependencyResolver, T> factory) 

返回值必须的一个实例T接口和一个例子多是这个样子:

var factory = new IdentityServerServiceFactory();

factory.TokenSigningService = new Registration<ITokenSigningService>(resolver =>

    new MyCustomTokenSigningService("SomeSigningKeyValue"));

Ø 得到其余依赖项

虽然这种方法容许您最灵活地建立你的服务,你还可能须要使用其余服务。 这就是IDependencyResolver用于。 它容许您从在你的回调函数获得服务。 例如,若是您的自定义客户端存储须要依赖于另外一个服务在IdentityServer,它能够是这样得到的:

var factory = new IdentityServerServiceFactory();

factory.TokenSigningService = new Registration<ITokenSigningService>(resolver =>

    new MyCustomTokenSigningService("SomeSigningKeyValue",

 resolver.Resolve<ICustomLogger>()));

Ø 叫依赖

最后,当经过注册自定义依赖关系IdentityServerServiceFactoryRegister()方法,能够命名的依赖关系。 这个名字是表示经过name构造函数的参数Registration类。 这仅仅是用于自定义注册和名称只能解决依赖关系时使用IDependencyResolver在自定义工厂回调。

命名的依赖多是有用的注册相同的多个实例T提供一种机制来实现所需的。 例如:

string mode = "debug"; // or "release", for example

var factory = new IdentityServerServiceFactory();

factory.Register(new Registration<ICustomLogger,MyFileSystemLogger>("debug"));

factory.Register(new Registration<ICustomLogger, MyDatabaseLogger>("release"));

factory.TokenSigningService = new Registration<ITokenSigningService>(resolver =>

    new MyCustomTokenSigningService(resolver.Resolve<ICustomLogger>(mode)));

在这个例子中,mode做为配置国旗impelmentation的影响ICustomLogger在运行时将使用。

v 实例化与登记模式

Registration类容许服务显示多少的实例将建立的服务。 的Mode属性是一个枚举这些可能的值:

  • InstancePerHttpRequest
    • 每一个HTTP请求将建立一个实例。 这意味着,若是在单个服务请求两次依赖链则将共享相同的实例。
  • InstancePerUse
    • 将建立一个实例/位置服务是必要的。 这意味着,若是在单个服务请求两次依赖链而后将建立两个单独的实例。
  • Singleton
    • 只有一个实例将被建立。 当使用这种模式是自动分配Registration接受一个单例实例做为构造函数参数。

v 客户端缓存结果、范围和用户存储

有各类各样的商店容许IdentityServer从数据库加载数据。 鉴于IdentityServer的通常解耦设计,能够屡次调用api加载数据IdentityServer相同的HTTP请求。 这可能招致没必要要的往返数据库。 考虑到这种可能性,IdentityServer定义了一个缓存接口,这样您就能够实现本身的缓存逻辑。 此外,IdentityServer提供了一个默认的缓存实现。

v 默认的缓存

IdentityServer提供的默认缓存是一个内存中的缓存和是可配置的缓存数据的时间到期。 这个默认缓存(虽然很简单)应该解决性能问题。 配置这个默认缓存,上有扩展方法IdentityServerServiceFactory:

l ConfigureClientStoreCache

l ConfigureScopeStoreCache

l ConfigureUserServiceCache

这些是重载要么不接受参数(使用默认的期满5分钟),或一个TimeSpan代表一个定制的到期值。 这些api使用这样的:

var factory = InMemoryFactory.Create(

    users:   Users.Get(),

    clients: Clients.Get(),

    scopes:  Scopes.Get());

 

factory.ConfigureClientStoreCache();

factory.ConfigureScopeStoreCache();

factory.ConfigureUserServiceCache(TimeSpan.FromMinutes(1));

这些方法应该被称为后分配到合适的商店IdentityServerServiceFactory,由于他们使用装饰模式包装实际的存储实现。

v 自定义缓存

若是须要自定义缓存实现(例如使用复述,),那么您能够实现的ICache<T>须要缓存的数据。 缓存接口定义了这个API:

  • Task SetAsync(string key, T item)
    • 的key和item缓存。
  • Task<T> GetAsync(string key)
    • 的key代表项目从缓存中访问。 一个null返回条目显示在缓存中没有条目。

IdentityServerServiceFactory上面描述的扩展方法也超载也接受Registration自定义缓存:

l ConfigureClientStoreCache(Registration<ICache<Client>> cacheRegistration)

l ConfigureScopeStoreCache(Registration<ICache<IEnumerable<Scope>>> cacheRegistration)

l ConfigureUserServiceCache(Registration<ICache<IEnumerable<Claim>>> cacheRegistration)

v 自定义视图

IdentityServer3向用户显示不一样的观点。 IdentityServer视图须要登陆,注销提示,退出系统,赞成,客户端权限和错误。 这些观点仅仅是web页面显示在浏览器中。 得到这些视图的标记,IdentityServer定义了IViewService接口。 视图服务是IdentityServer的一个可选的扩展点。

Ø 默认视图服务

能够找到这个话题的样本在这里

视图的默认实现IdentityServer是所使用的服务DefaultViewService。 各类资产(HTMLJavaScriptCSS和字体)组成的观点从嵌入式资源在IdentityServer组装。

DefaultViewService容许必定数量的定制。

CSS和脚本定制

定制的一个简单的方法是托管的应用程序能够提供一个列表的CSSJavaScript文件包含在默认的web页面。 这容许品牌而不须要彻底取代资产自己。

DefaultViewServiceOptions类是用来表示这些CSSJavaScript文件经过StylesheetsScripts列表:

var viewOptions = new DefaultViewServiceOptions();

viewOptions.Stylesheets.Add("/Content/Site.css");

的路径传递给Add能够是相对于IdentityServer的基本路径前缀路径的“~”(“~ /道路/ file.css”),或者能够经过加前缀host-relative路径的路径用“/”(“/道路/ file.css”)。 绝对url添加支持,只要他们IdentityServerCSP的选项

而后使用DefaultViewServiceOptions有一个ConfigureDefaultViewService扩展方法IdentityServerServiceFactory。 这个助手方法使用依赖注入系统注册DefaultViewService及其依赖项的基础上选择:

var viewOptions = new DefaultViewServiceOptions();

viewOptions.Stylesheets.Add("/Content/Site.css"); 

var factory = new IdentityServerServiceFactory();

factory.ConfigureDefaultViewService(viewOptions);

HTML定制

替换整个视图

DefaultViewService容许HTML的定制。 默认视图能够经过建立HTML文件在一个覆盖”assets托管应用程序库中的文件夹目录。 文件包含在所在地的名字匹配正在呈现的视图(例如login视图将寻找一个文件命名login.html)。 若是这些文件存在,那么他们负责呈现的HTML视图的所有。

替换部分的观点

呈现其默认视图时,DefaultViewService使用模板机制(相似于MVC)布局模板。 有一个共享的布局视图,还有单独的部分的观点(一个为每一个页面须要显示)conatin里面的内容呈现的布局。 当一个视图呈现这两个合并在一块儿在服务器发出一个HTML文档。

这一点本讨论的是当自定义HTML,而不是取代整个HTML文档能够取代部分视图。 替换的部分视图文件位于assets文件夹只须要杰出的在名字前面加上与underscope(如。_login.html)。 这将会使用默认的布局模板,但使用自定义局部视图。 它将被合并到布局模板合并后的HTML呈现到浏览器。

除了可以取代部分视图,也能够替换默认布局模板自己。 这能够经过建立一个命名的文件_layout.htmlassets文件夹中。 的DefaultViewService将使用任何组合的自定义布局或部分观点发现与默认的嵌入式文件系统合并资产呈现请求的视图。

缓存

自定义视图将默认缓存的内存,因此若是文件被改变了,那么它将须要一个应用程序从新启动加载任何更新的HTML。 这种行为能够经过设置被禁用CacheViews财产falseDefaultViewServiceOptions前面所述。

自定义视图加载程序

最后,若是assets文件系统上的文件夹不可取,那么您能够实现您本身的自定义存储视图经过implmenetingIViewLoader接口。 这是做为一个配置Registration<IViewLoader>DefaultViewServiceOptions

Ø 自定义视图服务

能够找到这个话题的样本在这里

若是托管应用程序须要彻底控制视图(HTMLCSSJavaScript)就能够实现的IViewService控制的全部标记呈现视图。 自定义视图服务将被注册ViewService财产的IdentityServerServiceFactory

的方法IViewService每一个预计将产生一个接口Stream包含UTF8编码标记显示的各类视图(登陆、赞成等)。 这些方法都接受做为参数模型特定的视图(如呈现LoginViewModel,或者一个ConsentViewModel)。 这个模型提供了上下文信息,极可能须要向用户提供(例如客户端和范围在赞成的观点,或错误消息错误观点,URL提交凭证登陆)

大多数视图将须要请求回到IdentityServer内不一样的端点。 这些GETPOST请求必须包含相同的输入,默认视图发送到服务器。 url中包含的各类模型。

反跨站点请求伪造(Anti-XSRF)

后回服务器的视图必须包括一个form-URL-encoded anti-xsrf令牌的请求主体。 每一个包含一个相关的模型AntiForgeryTokenViewModel对象的NameValue预计的参数。 自定义视图必须包括这些当提交用户的输入数据。

v 本地化的消息

消息IdentityServer建立能够经过实施本地化(或简单地取代)ILocalizationService接口。 它定义了一个API:

l string GetString(string category, string id)

这个API是经过了category的消息。 IdentityServer只定义了三个类:

public static class LocalizationCategories

{

    public const string Messages = "Messages";

    public const string Events = "Events";

    public const string Scopes = "Scopes";

}

id参数显示类别的特定信息。 各类标识符,常量定义的使用IdentityServer3.Core.Resources名称空间。 举例来讲,这里是一个简短的片断的常量(咨询完整列表的代码):

namespace IdentityServer3.Core.Resources

{

    public class MessageIds

    {

            public const string ClientIdRequired = "ClientIdRequired";

            public const string ExternalProviderError = "ExternalProviderError";

            public const string Invalid_scope = "Invalid_scope";

            public const string InvalidUsernameOrPassword = 

                                                       "InvalidUsernameOrPassword";

            public const string MissingClientId = "MissingClientId";

            // ...

  }

}

默认的实现ILocalizationService

v CSP

IdentityServer合并使用内容安全政策(CSP)的全部HTML页面显示。

Ø CspOptions

IdentityServer3容许托管应用程序配置CspOptionsIdentityServerOptions控制CSP的行为。 如下是可配置的设置:

l Enabled:指示是否启用或禁用CSP。 默认为true

l ScriptSrc:容许额外的script-src值被添加到默认策略。

l StyleSrc:容许额外的style-src值被添加到默认策略。

l FontSrc:容许额外的font-src值被添加到默认策略。

l ConnectSrc:容许额外的connect-src值被添加到默认策略。

CSP容许端点配置报告。 端点描述IdentityServer CSP提供了一个报告在这里

v 用户服务

这个话题能够找到的样本在这里

IdentityServer3定义了IUserService接口抽象底层身份管理系统用于用户。 它为用户提供了语义验证与本地帐户和外部帐户。 它还提供了身份和声称IdentityServer标记和用户所需信息端点。 此外,用户能够控制服务工做流在登陆时用户体验。

IUserService接口定义了这些方法:

  • AuthenticateLocalAsync
    • 此方法要求本地身份验证(当用户使用用户名和密码的对话框)。
  • AuthenticateExternalAsync
    • 这个方法被调用时,用户使用一个外部身份验证提供者。
  • PreAuthenticateAsync
    • 这个方法被调用以前登陆页面。 这容许您肯定用户应该由一些乐队的身份验证机制(例如客户端证书或信任的头)。
  • GetProfileDataAsync
    • 调用此方法时,关于用户要求(如令牌建立期间或经过用户信息端点)。
  • IsActiveAsync
    • 这个方法被调用时服务器须要肯定用户身份仍然被认为是有效的或活动(例如,若是用户的账户已停用,由于他们登陆)。
  • SignOutAsync
    • 这个方法被调用,当用户信号。

v 身份验证

三个的apiIUserService模型验证:AuthenticateLocalAsync,AuthenticateExternalAsync,PreAuthenticateAsync。 全部这三个api传递SignInMessage对象表明请求登陆上下文信息。 这些上下文属性一般从客户机传递到受权端点

SignInMessage包含这些属性可能感兴趣的用户服务。

l ClientId:客户端请求登陆标识符。

l IdP:外部身份提供商要求。

l Tenant:租户用户预计未来自。

l LoginHint:预期的用户名用户将使用登陆。

l DisplayMode:显示模式从受权请求。

l UiLocales:UI地区从受权请求。

l AcrValues:acr值经过受权请求。

除了SignInMessage,一些身份验证方法接受额外的参数。

AuthenticateLocalAsync若是用户输入凭据到本地调用IdentityServer登陆页面。 用户名和密码参数,以及SignInMessage

AuthenticateExternalAsync当外部调用身份提供商是用于验证。 的ExternalIdentity是经过了ExternalIdentity,以及SignInMessage

ExternalIdentity包含:

l Provider:外部身份提供者标识符。

l ProviderId:用户的惟一标识符提供的外部身份提供商。

l Claims:要求为用户提供从外部身份提供者。

PreAuthenticateAsync调用以前显示登陆页面,容许用户自定义服务,防止登陆页面显示。 这一般是因为一些外部参数,通知用户服务,用户应该已经登陆。 只有经过了SignInMessage

Ø 验证结果

全部的认证方法的返回值是一个AuthenticateResult。 返回的AuthenticateResult代表许多可能的结果之一。 使用构造函数重载,代表这些结果的选择。 结果是:

完整的登陆

彻底用户登陆身份验证API必须产生一个subject和一个name表明用户。 的subject是用户服务的用户和唯一标识符name是一个显示的名称 用户将显示在用户界面。

可选列表Claim也能够提供。 这些说法能够是任何额外的值,用户可能须要在其余api服务对用户的服务。

若是用户正在登陆,他们使用一个外部身份提供者,那么identityProvider参数也应表示。 这将是包括的idp声称的身份令牌和用户信息端点。 若是用户正在验证本地账户,而后不该使用该参数(默认的Constants.BuiltInIdentityProvider而不是使用)

还有一个可选的authenticationMethod参数的填充amrClaims。 这能够用来表示用户身份验证,如两因素身份验证,或客户端证书。 若是不经过,password假定为本地登陆。 对于外部登陆,而后的价值external将自动用于指示一个外部身份验证。

这些说法的完整(subject, name, idp, amr和列表Claim)是用于填充为用户发出的认证cookie IdentityServer。 这种身份验证cookie发行和管理经过使用武士刀cookie验证中间件的AuthenticationType的常数Constants.PrimaryAuthenticationType

ClaimsPrincipal从建立完整的登陆而后用做参数的其余apiIUserService。 这些apiGetProfileDataAsync, IsActiveAsync,SignOutAsync

部分登陆(重定向)

除了一个完整的登陆,身份验证api能够执行部分登陆。 部分登陆代表用户已经证实他们的身份,有本地账户,但还没有容许继续。 他们必须首先执行其余操做以前或提供其余数据彻底被容许登陆。 这是有用的定制用户的工做流以前让他们彻底登陆。 这多是有用的,迫使用户填写注册页面,改变密码,或者接受EULA以前让他们继续下去。

这部分执行登陆经过发行使用武士刀的部分登陆饼干饼干中间件的身份验证AuthenticationType的常数Constants.PartialSignInAuthenticationType

部分的登陆显示全部相同的参数如上所述登陆(即为一个完整的。subject, name, claims, amr,idp)以及redirectPath。 的redirectPath表明了一个自定义web页面提供的托管应用程序,用户将被重定向到。 在用户的web页面subjectname声称能够用来识别用户(除了全部其余Claims表示)。 为了得到这些说法,页面必须使用武士刀验证中间件来验证Constants.PartialSignInAuthenticationType身份验证类型,或仅仅是执行在同一个饼干路径IdentityServerweb服务器。

一旦用户自定义web页面已经完成他们的工做,他们能够被重定向回IdentityServer继续登陆过程。 提供的URL将用户重定向回的ClaimsConstants.PartialSignInAuthenticationType身份验证类型并肯定的要求类型Constants.ClaimTypes.PartialLoginReturnUrl

外部登陆(重定向)

可能用户执行外部认证,可是没有为用户本地账户。 一个定制的用户服务能够选择重定向用户没有本地账户。 这是经过建立一个执行AuthenticateResult与重定向ExternalIdentity传递到AuthenticateExternalAsyncAPI。 这个执行部分登陆(如经过以上PartialSignInAuthenticationType),但没有在发布了饼干。 取而代之的是Claims的类型external_provider_user_id(或经过Constants.ClaimTypes.ExternalProviderUserId),Issuer是外部提供者标识符的值是外部提供者的用户标识符。 这些值能够用于建立一个本地账户并将外部帐户相关联。

一旦用户完成注册自定义web页面,就能够重定向回IdentityServer经过相同的PartialLoginReturnUrl如上所述。

登陆错误

最后,验证api能够提供一个错误,将会显示在登陆视图。 这是表示经过建立AuthenticateResult使用构造函数,它接受一个string(错误)做为其参数。

 

 

第九章部署

请注意本文档是正在进行的工做。 随时添加新的内容。

v 数据保护

若是您正在运行在IIS,您须要同步机键。 若是您正在运行IIS以外您须要使用武士刀的web农场兼容的数据保护。

不幸的是,刀不附带一个开箱即用的。 IdentityServer包括一个数据保护的基础上 X。 509证书(X509CertificateDataProtector),您能够设置的选项类。

v 终止SSL

若是你想终止SSL负载均衡器,有两个相关的设置选项:

  • RequireSsl
    • 设置为false,容许非ssl负载均衡器和IdentityServer之间的链接。
  • PublicOrigin
    • 由于你的农场内部节点比公共可访问的地址有不一样的名称,IdentityServer不能使用它 连接的一代。 向公众洞穴这个属性的名字。

v 签名密钥

确保签名证书部署到全部节点。

v 配置数据

做用域的配置数据,客户和用户必须同步。

他们要么是静态的,你改变经过持续部署配置数据,或者你使用持久层 实体框架回购(MongoDB或社区的贡献)

v 操做数据

一些功能须要操做数据的共享数据库,即受权代码,参考令牌和刷新令牌。 若是你使用这些功能须要一个持久层。 你可使用咱们implemenation实体框架。

v 缓存

IdentityServer有一个简单的内置内存缓存。 这是有用的但不像它能够优化网络农场。 你能够插入本身的缓存实现ICache

第十章实体框架支持客户、范围和操做数据

概述

支持实体框架IdentityServer来源回购。

v 配置客户机和范围

若是范围或客户数据须要从数据库加载(而不是使用内存配置),而后提供一个基于实体框架的实现IClientStoreIScopeStore服务。更多的信息

v 操做数据

另外,强烈建议操做数据(如受权码,刷新令牌,参考标记,和用户赞成)被保存在数据库中。 所以,咱们也有实体框架的实现IAuthorizationCodeStore, ITokenHandleStore, IRefreshTokenStore,IConsentStore服务。更多的信息

v 客户和范围

v 商店

Ø ClientStore

ClientStoreEF-based实现吗IClientStore接口。 它能够单独使用的ScopeStore

Ø ScopeStore

ScopeStoreEF-based实现吗IScopeStore接口。 它能够单独使用的ClientStore

v 登记

使用的商店,他们须要注册。 上有扩展方法IdentityServerServiceFactory容许商店都进行配置。 全部的扩展方法接受一个EntityFrameworkServiceOptions它包含这些属性:

l ConnectionString:配置链接字符串的名字.config文件。

l Schema:一个可选的数据库模式使用的表。 若是没有提供,则将使用默认数据库。

配置独立商店,这段代码可使用:

var efConfig = new EntityFrameworkServiceOptions {

   ConnectionString = "SomeConnectionName",

   //Schema = "someSchemaIfDesired"};

var factory = new IdentityServerServiceFactory();

factory.RegisterClientStore(efConfig);

factory.RegisterScopeStore(efConfig);

若是两个商店将使用相同的EntityFrameworkServiceOptions,而后提供一个方便的扩展方法:

var efConfig = new EntityFrameworkServiceOptions {

   ConnectionString = "SomeConnectionName",

   //Schema = "someSchemaIfDesired"};

var factory = new IdentityServerServiceFactory();

factory.RegisterConfigurationServices(efConfig);

第十一章操做数据

IdentityServer3的许多特性的数据库须要坚持各类运营数据。 这包括受权码,刷新令牌,参考标记和用户赞成。

登记

有各类各样的商店将持久化操做数据。 这些都是配置了一个扩展方法IdentityServerServiceFactory。 全部的扩展方法接受一个EntityFrameworkServiceOptions它包含这些属性:

l ConnectionString:配置链接字符串的名字.config文件。

l Schema:一个可选的数据库模式使用的表。 若是没有提供,则将使用默认数据库。

配置操做数据存储可使用这段代码:

var efConfig = new EntityFrameworkServiceOptions {

   ConnectionString = "SomeConnectionName",

   //Schema = "someSchemaIfDesired"};

var factory = new IdentityServerServiceFactory();

factory.RegisterOperationalServices(efConfig);

v 数据清理

大部分的操做数据已通过期。 极可能须要移除这个陈旧的数据。 能够承载IdentityServer之外的应用程序或数据库自己(经过各类机制)。 若是须要你执行这个清理应用程序代码,那么TokenCleanup类提供协助。 它接受一个EntityFrameworkServiceOptions和一个Int32时间间隔(以秒为单位)来配置陈旧的数据清理的频率。 它将异步链接到数据库,能够配置为:

var efConfig = new EntityFrameworkServiceOptions {

    ConnectionString = connString,

    //Schema = "foo"};

var cleanup = new TokenCleanup(efConfig, 10);cleanup.Start();

第十二章模式变化和迁移

IdentityServer3加强,数据库模式极可能会发生变化。 的预期模式变化,建议(和预期)托管应用程序负责处理这些模式会随着时间而改变。

实体框架提供了迁移做为一个方法来处理模式变化和更新您的数据库与变化。

v dbcontext

有三种不一样的DbContext派生类中包含的EF的实现。 它们是:

l ClientConfigurationDbContext

l ScopeConfigurationDbContext

l OperationalDbContext

这些须要,由于数据库上下文类(即在一个不一样的装配。Thinktecture.IdentityServer3.EntityFramework比托管应用程序)

v 使迁移

迁移必须为每一个数据库建立上下文类。 使迁移的全部数据库上下文类,可使用下面的命令从包管理器控制台:

Enable-Migrations -MigrationsDirectory Migrations\ClientConfiguration -ContextTypeName ClientConfigurationDbContext -ContextAssemblyName Thinktecture.IdentityServer3.EntityFramework -ConnectionStringName IdSvr3Config

 

Enable-Migrations -MigrationsDirectory Migrations\ScopeConfiguration -ContextTypeName ScopeConfigurationDbContext -ContextAssemblyName Thinktecture.IdentityServer3.EntityFramework -ConnectionStringName IdSvr3Config

 

Enable-Migrations -MigrationsDirectory Migrations\OperationalConfiguration -ContextTypeName OperationalDbContext -ContextAssemblyName Thinktecture.IdentityServer3.EntityFramework -ConnectionStringName IdSvr3Config

最初的模式必须被定义为每一个迁移(又一个),所以:

Add-Migration -Name InitialCreate -ConfigurationTypeName Host.Migrations.ScopeConfiguration.Configuration -ConnectionStringName IdSvr3Config

 

Add-Migration -Name InitialCreate -ConfigurationTypeName Host.Migrations.ClientConfiguration.Configuration -ConnectionStringName IdSvr3Config

 

Add-Migration -Name InitialCreate -ConfigurationTypeName Host.Migrations.OperationalConfiguration.Configuration -ConnectionStringName IdSvr3Config

而后能够建立数据库:

Update-Database -ConfigurationTypeName Host.Migrations.ClientConfiguration.Configuration -ConnectionStringName IdSvr3Config

Update-Database -ConfigurationTypeName Host.Migrations.ScopeConfiguration.Configuration -ConnectionStringName IdSvr3Config

Update-Database -ConfigurationTypeName Host.Migrations.OperationalConfiguration.Configuration -ConnectionStringName IdSvr3Config

一旦你的应用程序更新到新版本,那么您可使用Add-MigrationUpdate-Database更新到新模式。 检查英孚文档为更多的细节。

第十三章ws - federation

v 添加ws - federation支持

 

IdentityServer支持ws - federation充当一个身份提供商 容许外部身份验证经过ws - federation协议。 外部认证见在这里

这部分是关于添加ws - federation IdentityServer3身份提供者的功能。

ws - federation IdentityServer3支持是一个插件,使用的实现。 NET 4.5 System.IdentityModel。 服务组装。 您首先须要安装插件使用Nuget:

 install-package Thinktecture.IdentityServer3.WsFederation

而后您能够链接插件实现PluginConfiguration回调的IdentityServerOptions类是这样的:

  public void Configuration(IAppBuilder appBuilder)

 {

     var options = new IdentityServerOptions

     {

         SiteName = "Thinktecture IdentityServer3 with WsFed",

 

         SigningCertificate = Certificate.Get(),

         Factory = factory,

         PluginConfiguration = ConfigureWsFederation

     };

 

     appBuilder.UseIdentityServer(options);

 }

 

 private void ConfigureWsFederation(IAppBuilder pluginApp, IdentityServerOptions options)

 {

     var factory = new WsFederationServiceFactory(options.Factory);

 

     // data sources for in-memory services

     factory.Register(new Registration<IEnumerable<RelyingParty>>(RelyingParties.Get()));

     factory.RelyingPartyService = new Registration<IRelyingPartyService>(typeof(InMemoryRelyingPartyService));

 

     var wsFedOptions = new WsFederationPluginOptions

     {

         IdentityServerOptions = options,

         Factory = factory

     };

 

     pluginApp.UseWsFederationPlugin(wsFedOptions);

 }

 

至关于一个OpenID链接或在ws - federation OAuth2端叫作依赖方。 相似于其余内存工厂(在这里)ws - federation插件对检索的内置支持从一个内存中的服务依赖方。

看到在这里

v 定义依赖方

的RelyingParty类模型依赖方:

  • Name
    • 显示名称
  • Enabled
    • (默认为启用/禁用true)
  • Realm
    • 依赖方的惟一标识符
  • ReplyUrl
    • URL发送令牌回
  • TokenType
    • 类型的令牌(默认为SAML2),支持如下类型:
      • urn:oasis:names:tc:SAML:1.0:assertion (SAML 1.1)
      • urn:oasis:names:tc:SAML:2.0:assertion (SAML 2.0)
      • urn:ietf:params:oauth:token-type:jwt (JWT)
  • TokenLifeTime
    • 令牌一辈子在几分钟内(默认值为480)
  • EncryptingCertificate
    • 证书加密令牌(SAML)
  • IncludeAllClaimsForUser
    • 包括全部可用的用户令牌(而不是显式的映射)
  • DefaultClaimTypeMappingPrefix
    • 默认的输出要求类型若是前缀IncludeAllClaimsForUser但不存在显式的映射。
  • ClaimMappings
    • 容许设置一个映射表从内部Claims类型外向Claims类型(状况 有地图的冲动如name来http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name)
  • SamlNameIdentifierFormat
    • 容许设置SAML的SAML名称标识符格式名称ID
  • SignatureAlgorithm
    • 容许设置令牌的签名算法(默认为RSASHA256)
  • DigestAlgorithm
    • 容许设置摘要算法(默认为SHA256)

 

v 端点

ws - federation插件包含两个端点

v 登陆/出

这是主要的ws - federation端点的签字。

支持参数:

  • wa
    • 必须是wsignin1.0签署的或wsignout1.0对于签署
  • wtrealm
    • 依赖方的领域
  • wctx
    • 上下文是圆绊倒依赖方(相似state在OAuth2)
  • whr
    • 外部身份提供商使用的名称(跳过选择屏幕)

示例(可读性编码删除):

/wsfed?wa=wsignin1.0&wtrealm=rp1&whr=Google

v 元数据

返回元数据文档:

/wsfed/metadata

 

第十四章资源

v 资源

Ø 规范

OpenID链接核心规范

OAuth2规范

OAuth2威胁模型

Ø 文章

混合流

注销后重定向

注销后自动重定向

在Mono IdentityServer

测试Web api和邮递员

添加一个SAML2p外部身份验证提供者

斯科特·布雷迪:IdentityServer3独立实现pt。1

斯科特·布雷迪:IdentityServer3独立实现pt。2

斯科特·布雷迪:IdentityServer3独立实现pt。3

威廉姆斯Reece:FIPS听从性

Ø 视频

概述视频(预览版)

样品介绍视频(预览版)

引入IdentityManager

介绍OpenID链接,OAuth2 IdentityServer

Web API受权和访问控制——作对的! ?

身份管理与ASP。 净第1部分

身份管理与ASP。 净第2部分

Ø 培训

布鲁克和多明尼克的身份和访问控制的现代Web应用程序和api车间

创建和确保一个RESTful api的多个客户端ASP。 净在PluralSight

 

v 社区插件

MongoDb支持

ElasticSearch / Kibana EventService

为多种语言本地化服务(包括海盗!)

复述,缓存

Powershell Cmdlets实体框架的持久性

第十五章中间件为外部认证

v 微软的武士刀

ws - federation

OpenID链接

谷歌

推特

微软帐户

脸谱网

v SAML2p

KentorIT认证服务——看到也博客

v 其余社区的贡献

OWIN OAuth提供者

相关文章
相关标签/搜索