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
l 大局
l 术语
l 特性和规格
l 包装
l 开始:建立最简单的OAuth2受权服务器,客户端和API
l 概述
l 选项
l 服务工厂
l 内存中的工厂
l 客户
l 身份验证选项
l 身份提供者
l hst
l 歌珥
l 日志记录
l 事件
l 受权/身份验证
l 令牌
l 用户信息
l 发现
l 注销
l 令牌撤销
l 访问令牌验证
l 身份令牌验证
l CSP错误报告
l 刷新令牌
l 注册服务
l DI的服务
l 自定义视图
l 本地化的消息
l CSP
l 用户服务
l 部署
l 概述
l 客户和范围
l 操做数据
l 模式变化和迁移
l 定义依赖方
l 端点
l 概述
l 社区插件
l 中间件为外部认证
大多数现代应用程序看起来或多或少是这样的:
典型的交互:
l 浏览器与web应用程序通讯
l Web应用程序与Web api(有时本身,有时表明一个用户)
l 基于浏览器的应用程序与web api通讯
l 本机应用程序与web api通讯
l 基于服务器的应用程序与web api通讯
l Web api与Web api(有时本身,有时表明一个用户)
一般每一层(中间层和后端,前端)和保护资源 实现身份验证和/或受权,一般针对同一用户存储。
这就是为何咱们没有实现这些基本安全功能的业务应用程序/端点自己, 而是关键功能的外包服务,安全令牌服务。
这将致使如下安全架构和使用协议:
这将安全问题划分为两个部分。
u 身份验证
身份验证是必要的,当一个应用程序须要知道当前用户的身份。 一般这些应用程序表明用户管理数据,须要确保用户只能 他被容许访问数据。 最多见的例子(经典)web应用程序 但本机和JS-based应用程序也须要进行身份验证。
最多见的身份验证协议SAML2p,ws - federation,OpenID链接——SAML2p 最受欢迎和最普遍的部署。
OpenID链接是最新的三个,但通常认为是,由于它有将来 现代应用最有潜力的产业。 它从一开始就为移动应用程序场景 和被设计成API友好。
u API访问
应用程序有两个基本方法,它们与api使用应用程序标识, 或受权用户的身份。 有时两方面须要的总和。
OAuth2是一种协议,它容许应用程序请求访问令牌从安全令牌服务和使用它们 与api。 这下降了复杂性在客户机应用程序的api 能够集中的身份验证和受权。
OpenID和OAuth2——更好的联系在一块儿
OpenID链接和OAuth2很是类似——事实上OpenID是一个链接扩展OAuth2之上。 这意味着您能够将两个基本安全问题-认证和API访问到一个单独的协议 一般一个往返安全令牌服务。
这就是为何咱们相信OpenID的组合链接和安全的现代OAuth2是最好的方法 应用程序在可预见的将来。 IdentityServer3是这两个协议的一个实现 高度优化的解决今天的移动的典型安全问题,本机和web应用程序。
规范、文档对象模型使用一个特定的术语,你应该知道的。
IdentityServer OpenID提供者链接,它实现了OpenID链接协议(以及OAuth2)。
不一样的文献使用不一样的条款相同的角色,你也可能找到安全令牌服务, 身份提供者,受权服务器,IP-STS等等。
但总而言之都是同样的:一个软件问题给客户的安全令牌。
IdentityServer有不少工做和功能,包括:
l 验证用户使用本地账户存储或经过外部身份提供者
l 提供会话管理和单点登陆
l 管理和认证的客户
l 问题客户身份和访问令牌
l 验证令牌
客户端是一个软件,请求令牌从IdentityServer——对一个用户进行身份验证或 一般用于访问资源(也称为依赖方或RP)。 客户端必须注册与OP。
客户是web应用程序的例子,本地移动或桌面应用程序,水疗,服务器进程等。
用户是一我的类,使用一个注册客户机来访问他或她的数据。
做用域标识符为客户想要访问的资源。 这个标识符在一个发送给OP 身份验证或令牌的请求。
默认状况下容许每一个客户机请求令牌为每一个范围,可是你能够限制。
他们有两种口味。
请求关于用户的标识信息(又名声称),如他的名字或电子邮件地址被建模为一个范围的OpenID链接。
若有一个范围profile首选,包括名字、姓、用户名、性别、证件照以及更多。 你能够读到标准范围在这里你能够建立本身的范围IdentityServer模型本身的需求。
资源范围肯定web api(也称为资源服务器)——你能够如命名范围calendar表明你的日历API。
客户请求令牌的相机会取决于请求的范围,OP会返回一个身份令牌,一个访问令牌,或二者兼而有之。
能够经过客户端验证身份令牌。
它包含有关用户的信息和细节在OP用户身份验证。 身份令牌表明一个成功的身份验证。
一个访问令牌能够由资源进行验证。
客户请求访问令牌和转发他们的API。 访问令牌包含客户端和用户信息(若是存在)。 api使用这些信息来受权访问他们的数据。
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)
IdentityServer由nuget包的数量。
包含核心IdentityServer对象模型、服务和服务器。 只包含核心支持内存配置和用户的商店,可是你能够经过配置插件支持其余商店。 这是另外一个回购和包。
存储配置数据(客户和范围)以及运行时数据(赞成,令牌处理,刷新令牌)。
(社区贡献)MongoDbgithub
支持身份管理库。
MembershipReboot nuget | github
ASP.Net Identity nuget | github
协议插件。
OWIN中间件api。 提供了一种简便的方法来验证访问令牌和实施范围的要求。
此外,咱们发布dev /临时构建MyGet。 Visual Studio下面添加到你若是你想给他们一个尝试:
https://www.myget.org/F/identity/
这个介绍的目的是建立简单的IdentityServer安装做为一个OAuth2受权服务器。 这是应该让你开始的一些基本特性和配置选项(能够找到完整的源代码在这里)。 还有其余更高级的演练的文档以后你能够作。 本教程包括:
l 建立一个自托管IdentityServer
l 为应用程序设置客户服务通讯使用应用程序账户和表明一个用户
l 注册一个API
l 请求访问令牌
l 调用一个API
l 验证一个访问令牌
首先,咱们将建立一个控制台主机和设置IdentityServer。
首先建立一个标准的控制台应用程序并添加IdentityServer经过nuget:
install-package Thinktecture.IdentityServer3
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被实现为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。 为此咱们将武士刀自托管包添加到控制台应用程序:
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...。
在这一部分,咱们将添加一个简单的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由于必要的访问令牌是失踪。
在接下来的部分,咱们将添加一个简单的控制台客户端请求一个访问令牌和使用进行身份验证的api。
首先添加一个新的控制台项目和安装nuget包OAuth2客户机助手库:
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"}在您的控制台。
到目前为止,客户端请求的访问令牌自己,没有用户。 让咱们介绍一我的。
用户服务管理用户,对于此示例,咱们将使用简单的内存的用户服务。 首先咱们须要定义一些用户:
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"
}
};
}}
Username和Password用于验证用户, 的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())
}
}
};
}}
当一我的类,将包含访问令牌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。
这演练了一个很是简单的OAuth2场景。 下一个你能够试试:
l 其余流,如隐式、代码或混合。 他们都是推进者等高级场景联合会和外部的身份
l 链接到您的用户数据库,经过编写本身的用户服务或使用咱们的开箱即用的支持ASP.Net Identity和MembershipReboot
l 客户端和范围配置存储在一个数据存储。 咱们有现成的实体框架支持。
l 使用OpenID链接和添加身份验证和身份令牌标识范围
l 本教程将引导您完成必要的步骤来获得一个最小IdentityServer启动并运行。 为简单起见,咱们将主机IdentityServer和客户端在同一web应用程序,这可能不是一个很是现实的场景中,但可让你开始没有使它太复杂。
能够找到完整的源代码在这里。
在第一部分,咱们将建立一个简单的MVC应用程序并经过IdentityServer添加身份验证。 而后咱们会仔细看看Claims,Claims转换和受权
在Visual Studio 2013中,建立一个标准的MVC应用程序和身份验证设置为“无身份验证”。
如今您能够切换项目SSL使用属性窗口:
重要的别忘了更新在您的项目中开始URL属性。
IdentityServer基于OWIN /刀和分布式Nuget包。 将其添加到新建立的web主机,安装如下两个方案:
install-package Microsoft.Owin.Host.Systemweb
install-package Thinktecture.IdentityServer3
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——这能够经过提供一个简单的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添加到您的网站。 配置,不然咱们的一些嵌入式资产由IIS将不能正确加载:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" /></system.webServer>
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"
});
启动认证与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>
点击连接将触发身份验证。 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中间件要求两个范围:openid和profile——这就是为何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类型映射到.net的ClaimTypes类类型。 你能够关掉这个行为与如下代码行(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控制器和一个属性,表示这一行动将执行Read的ContactDetails资源:
[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")]要知道网站能够被扔进一个无限重定向循环当当前用户身份验证,但不属于其中的一个角色或用户进入Authorize在MVC 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在谷歌的开发者控制台。 这包括几个步骤。
首先导航到:
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与谷歌声称丢失时登陆。 颇有意义,由于谷歌没有角色的概念。 作好准备,并不是全部的身份提供者将提供相同的声明类型。
在这部分咱们将添加一个Web API的解决方案。 API将由IdentityServer担保。 接下来咱们的MVC应用程序将调用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);
}}
一如既往地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发现文档(元数据)。
接下来咱们须要注册的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;
}}
接下来咱们将调用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包含两个部分:
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使用用户的身份。 这是经过添加完成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如今工做表明一个用户:
若是你如今添加范围要求role到sampleApi范围——用户的角色将被包括在访问令牌:
new Scope{
Enabled = true,
Name = "sampleApi",
Description = "Access to a sample API",
Type = ScopeType.Resource,
Claims = new List<ScopeClaim>
{
new ScopeClaim("role")
}}
新 ScopeClaim(“角色”)
}}
IdentityServer3打包为中间件和使用典型的“选项”模式配置:
public void Configuration(IAppBuilder appBuilder){
var options = new IdentityServerOptions
{
SigningCertificate = Certificate.Get(),
Factory = factory,
};
appBuilder.UseIdentityServer(options);}
的IdentityServerOptionsIdentityServer类包含全部配置。 一部分由发行人的简单属性名称或网站标题,您能够从任何你认为合适的来源(静态代码中,配置文件或数据库)。 另外一部分是所谓的服务工厂充当注册IdentityServer内部处理的某些方面。
网页提供的文件做为嵌入式IdentityServer议会内部的资产。 当在IIS托管或IIS Express容许这些文件送达RAMMFAR(runAllManagedModulesForAllRequests)须要在web . config中启用:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
看到样品
的IdentityServerOptions 类的顶层容器IdentityServer的全部配置设置。
IdentityServer3包含许多功能实现OpenID和OAuth2链接。 许多这些功能设计,这样他们就能够被取代。 这将是有用的场景缺省逻辑不匹配托管应用程序的需求,或者只是应用程序但愿提供一个彻底不一样的实现。 事实上,有些在IdentityServer3扩展点,须要提供的托管应用程序(如存储配置数据或验证的身份管理实现用户的凭证)。
的Thinktecture.IdentityServer.Core.Configuration.IdentityServerServiceFactory拥有全部这些构建块,必须提供在启动时使用IdentityServerOptions类(见在这里有关配置选项的更多信息)。
扩展点分为三类。
的InMemoryFactory容许设置一个服务工厂经过为用户提供内存存储,客户和范围(见在这里)。
看到在这里有关注册定制服务的更多信息和存储的实现。
内存厂是一个简单的方法来获得一个测试/ dev版本IdentityServer启动并运行。
当你建立in-mem工厂你能够提供一个静态列表Client, Scope和InMemoryUser。 全部其余数据(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应用程序(连接)。
除了有不少设置控制刷新令牌——看到的行为在这里
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}
还能够指定范围声称进入相应的令牌-ScopeClaim类具备如下属性:
的例子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)
}};
这个话题能够找到的样本在这里
的AuthenticationOptions是一个属性的吗IdentityServerOptions自定义登陆和注销的观点和行为。
IdentityServer支持使用外部身份验证提供者。 外部身份验证机制必须封装在一个武士刀认证中间件。
武士刀自己附带的中间件为谷歌、Facebook、Twitter、微软帐户,ws - federation和OpenID链接,但也有社区开发中间件)(包括雅虎、LinkedIn和SAML2p)。 看到这里的选项列表。
为外部提供者配置中间件,添加一个方法接受一个项目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);
基于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);
HTTP严格的运输安全(hst)是网络安全的一个重要方面。 IdentityServer3提供了一个配置选项包括hst头在它全部的HTTP响应。 要启用,使用UseHsts扩展方法IAppBuilder在你OWIN配置:
public void Configuration(IAppBuilder app){
app.UseHsts();
// ...}
若是你想设置过时(max-age),而后UseHsts过载,接受吗int的天数, 或者一个TimeSpan为一个自定义的持续时间。 的值0或TimeSpan.Zero能够用来清洗hst浏览器缓存。 默认过时30天。
许多端点IdentityServer将经过Ajax调用从JavaScript访问。 鉴于IdentityServer极可能比这些客户托管在一个不一样的起源,这意味着跨源资源共享(歌珥)将是一个问题。
IdentityServer3容许托管应用程序来实现ICorsPolicyService肯定歌珥政策。 该服务注册的IdentityServerServiceFactory。
单一方法ICorsPolicyService是:
你能够实现一个自定义的实如今任何你认为合适的方式来肯定若是调用起源是被容许的。
有两种实现提供从IdentityServer核心:
有一个最后的实现提供了从IdentityServer3.EntityFramework:
在版本1.0.0 IdentityServer的CorsPolicy是惟一的方法来支持歌珥和如今已经弃用上述歌珥政策服务。 下面的文档维护,由于1.0.0特性仍然支持,但在将来的版本将被删除。
IdentityServer3容许托管应用程序配置CorsPolicy在IdentityServerOptions控制容许哪些起源。
AllowedOrigins
的CorsPolicy有两种方法能够指定容许哪些起源。 第一个是AllowedOrigins主机名称的集合。 这是有用的,若是在应用程序启动时间的起源是已知的(硬编码或可能从数据库加载)。
var idsvrOptions = new IdentityServerOptions();
idsrvOptions.CorsPolicy.AllowedOrigins.Add("http://myclient.com");
idsrvOptions.CorsPolicy.AllowedOrigins.Add("http://myotherclient.org);
第二个方法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};
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。
的LoggingOptions类具备如下设置:
警告 EnableHttpLogging可能的冲突与其余框架加载到相同的web应用程序(它确定与MVC)。 您不能使用HTTP记录在这种状况下。
如下代码片断添加到您的配置文件将全部日志消息到一个简单的文本文件。 咱们使用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>
如下代码片断添加到您的配置文件。 您可使用服务跟踪查看器的工具。 净SDK检查跟踪文件。
<sources>
<source name="Thinktecture.IdentityServer"
switchValue="Information, ActivityTracing">
<listeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "trace.svclog" />
</listeners>
</source></sources>
您还可使用日志系统在您本身的代码的可扩展性。
添加一个静态ILog实例类
private readonly static ILog Logger = LogProvider.GetCurrentClassLogger();
使用日志记录器记录你的消息
Logger.Debug("Getting claims for identity token");
IdentityServer在运行时引起了一系列的事件,如:
l 成功/失败身份验证(资源全部者流,pre、片面、本地和外部)
l 令牌发出(身份、访问刷新令牌)
l 令牌处理相关事件(受权代码刷新令牌发出/赎回/刷新)
l 许可撤销
l 端点成功/失败
l 过时无效/没有签名证书
l 未处理的异常和内部错误
l CSP错误报告的浏览器。 看到CSP为更多的信息。
默认状况下这些事件转发到日志提供者——配置 一个定制的事件服务能够处理或以任何方式提出适合环境。
的EventsOptions类具备如下设置(默认false):
受权端点能够用来请求访问令牌或受权码(隐式和受权代码流)。 你可使用一个web浏览器或web视图开始这个过程。
看到规范。
可读性(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
令牌端点能够用于以编程方式请求或刷新令牌(资源全部者凭证流密码,受权代码流,客户端凭证流和自定义受权类型)。
看到规范。
全部请求令牌端点必须通过身份验证——要么经过基自己份验证经过客户机id和秘密 或添加client_id和client_secret字段的身体。
当提供client_id和client_secret在Authorization头预计:
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
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"
]
}
发现端点能够用来检索关于IdentityServer——它返回元数据信息,如发行人名称、关键材料,支持范围等。
看到规范
GET /.well-known/openid-configuration
重定向到注销端点扫清了身份验证会话和饼干。
您能够经过如下的端点可选参数:
/connect/endsession?id_token_hint=...&post_logout_redirect_uri=https://myapp.com
这个端点容许撤销访问令牌(仅参考标记)和刷新令牌。 它实现了令牌撤销规范(RFC 7009)。
支持参数:
使用一个支持的请求必须通过身份验证的客户端身份验证方法。
例子:
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
访问令牌验证端点能够用来验证参考标记。 它也能够用来验证独立JWT若是消费者没有支持适当的JWT或加密库。
GET /connect/accesstokenvalidation?token=<token>
一个成功的响应将返回一个状态码200和相关申请令牌。 一次不成功的响应将返回一个400错误消息。
还能够经过一个范围,预计将在令牌:
GET /connect/accesstokenvalidation?token=<token>&expectedScope=calendar
身份令牌验证端点能够用来验证身份令牌。 这是有用的为客户,没法得到适当的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"
}
CSP容许端点配置报告。 IdentityServer CSP的错误记录浏览器提供一个端点报告。 这些CSP错误将提升事件在事件系统。
CSP报告特性能够经过设置禁用EnableCspReportEndpoint财产false在EndpointOptions的一个属性是什么IdentityServerOptions。
l 刷新令牌支持如下流:受权代码,混合动力和资源全部者凭证流密码。
l 客户须要容许请求offline_access范围刷新令牌。
l 请求offline_access范围(经过代码或资源全部者流)
l 使用刷新令牌refresh_token格兰特
IdentityServer3提供了许多扩展点用于存储数据,验证逻辑和通用功能 支持IdentityServer所需的操做做为一个令牌服务。 这些不一样的扩展点统称为“服务”。
看到在这里服务的完整列表。
三是强制性的,必须配置的服务实现者,他们是:
l 用户服务(IUserService)
l 客户端存储(IClientStore)
l 存储(范围IScopeStore)
咱们提供一个简单的内存版本的这三个服务以及支持经过回购或社区项目相关的数据存储。 看到在这里为更多的细节。
你能够取代全部服务和注册额外定义的。 这是封装的Registration类。 一个Registration表明一种IdentityServer得到您的服务的一个实例。
根据您的服务的设计您可能想要对每一个请求一个新实例,使用单例, 或者你可能须要特殊的实例化逻辑每次实例是必要的。 为了适应这些不一样的可能性,Registration类提供了许多不一样的构造函数来注册服务:
var factory = new IdentityServerServiceFactory();factory.UserService = new Registration<IUserService, MyCustomUserService>();
看到这个页面依赖注入(DI)页面了解更多细节。
在全部状况下,除了单,若是您的服务实现IDisposable,而后Dispose
这个话题能够找到的样本在这里
IdentityServer3已经为各类服务扩展点。 默认的实现这些服务被设计为与其余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>();
定制服务也可能依赖于你本身的类型。 这些也能够注入只要他们已经配置了IdentityServer的依赖注入系统。 这是经过添加新注册使用IdentityServerServiceFactory的Register()方法。 例如,若是你须要定制日志记录器服务:
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>());
在上面的例子中注入类型是ICustomLogger和impelemntation是MyCustomDebugLogger。 若是没有设计定制服务接口实现单独的合同,而后注册的具体类型自己能够被注入。
例如,若是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具体类型是被注入依赖的类型。
若是你的服务是必要的人工构造(如您须要传递特定参数的构造函数),而后您可使用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>()));
最后,当经过注册自定义依赖关系IdentityServerServiceFactory的Register()方法,能够命名的依赖关系。 这个名字是表示经过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在运行时将使用。
的Registration类容许服务显示多少的实例将建立的服务。 的Mode属性是一个枚举这些可能的值:
有各类各样的商店容许IdentityServer从数据库加载数据。 鉴于IdentityServer的通常解耦设计,能够屡次调用api加载数据IdentityServer相同的HTTP请求。 这可能招致没必要要的往返数据库。 考虑到这种可能性,IdentityServer定义了一个缓存接口,这样您就能够实现本身的缓存逻辑。 此外,IdentityServer提供了一个默认的缓存实现。
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,由于他们使用装饰模式包装实际的存储实现。
若是须要自定义缓存实现(例如使用复述,),那么您能够实现的ICache<T>须要缓存的数据。 缓存接口定义了这个API:
的IdentityServerServiceFactory上面描述的扩展方法也超载也接受Registration自定义缓存:
l ConfigureClientStoreCache(Registration<ICache<Client>> cacheRegistration)
l ConfigureScopeStoreCache(Registration<ICache<IEnumerable<Scope>>> cacheRegistration)
l ConfigureUserServiceCache(Registration<ICache<IEnumerable<Claim>>> cacheRegistration)
IdentityServer3向用户显示不一样的“观点”。 IdentityServer视图须要登陆,注销提示,退出系统,赞成,客户端权限和错误。 这些观点仅仅是web页面显示在浏览器中。 得到这些视图的标记,IdentityServer定义了IViewService接口。 视图服务是IdentityServer的一个可选的扩展点。
能够找到这个话题的样本在这里
视图的默认实现IdentityServer是所使用的服务DefaultViewService。 各类资产(HTML、JavaScript、CSS和字体)组成的观点从嵌入式资源在IdentityServer组装。
的DefaultViewService容许必定数量的定制。
CSS和脚本定制
定制的一个简单的方法是托管的应用程序能够提供一个列表的CSS和JavaScript文件包含在默认的web页面。 这容许品牌而不须要彻底取代资产自己。
的DefaultViewServiceOptions类是用来表示这些CSS或JavaScript文件经过Stylesheets和Scripts列表:
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.html在assets文件夹中。 的DefaultViewService将使用任何组合的自定义布局或部分观点发现与默认的嵌入式文件系统合并资产呈现请求的视图。
缓存
自定义视图将默认缓存的内存,因此若是文件被改变了,那么它将须要一个应用程序从新启动加载任何更新的HTML。 这种行为能够经过设置被禁用CacheViews财产false在DefaultViewServiceOptions前面所述。
自定义视图加载程序
最后,若是assets文件系统上的文件夹不可取,那么您能够实现您本身的自定义存储视图经过implmenetingIViewLoader接口。 这是做为一个配置Registration<IViewLoader>在DefaultViewServiceOptions。
能够找到这个话题的样本在这里
若是托管应用程序须要彻底控制视图(HTML、CSS、JavaScript等)就能够实现的IViewService控制的全部标记呈现视图。 自定义视图服务将被注册ViewService财产的IdentityServerServiceFactory。
的方法IViewService每一个预计将产生一个接口Stream包含UTF8编码标记显示的各类视图(登陆、赞成等)。 这些方法都接受做为参数模型特定的视图(如呈现LoginViewModel,或者一个ConsentViewModel)。 这个模型提供了上下文信息,极可能须要向用户提供(例如客户端和范围在赞成的观点,或错误消息错误观点,或URL提交凭证登陆)。
大多数视图将须要请求回到IdentityServer内不一样的端点。 这些GET和POST请求必须包含相同的输入,默认视图发送到服务器。 url中包含的各类模型。
反跨站点请求伪造(Anti-XSRF)
后回服务器的视图必须包括一个form-URL-encoded anti-xsrf令牌的请求主体。 每一个包含一个相关的模型AntiForgeryTokenViewModel对象的Name和Value预计的参数。 自定义视图必须包括这些当提交用户的输入数据。
消息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
IdentityServer合并使用内容安全政策(CSP)的全部HTML页面显示。
IdentityServer3容许托管应用程序配置CspOptions在IdentityServerOptions控制CSP的行为。 如下是可配置的设置:
l Enabled:指示是否启用或禁用CSP。 默认为true。
l ScriptSrc:容许额外的script-src值被添加到默认策略。
l StyleSrc:容许额外的style-src值被添加到默认策略。
l FontSrc:容许额外的font-src值被添加到默认策略。
l ConnectSrc:容许额外的connect-src值被添加到默认策略。
CSP容许端点配置报告。 端点描述IdentityServer CSP提供了一个报告在这里
这个话题能够找到的样本在这里
IdentityServer3定义了IUserService接口抽象底层身份管理系统用于用户。 它为用户提供了语义验证与本地帐户和外部帐户。 它还提供了身份和声称IdentityServer标记和用户所需信息端点。 此外,用户能够控制服务工做流在登陆时用户体验。
的IUserService接口定义了这些方法:
三个的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。 这些api是GetProfileDataAsync, IsActiveAsync,SignOutAsync。
部分登陆(重定向)
除了一个完整的登陆,身份验证api能够执行“部分登陆”。 部分登陆代表用户已经证实他们的身份,有本地账户,但还没有容许继续。 他们必须首先执行其余操做以前或提供其余数据彻底被容许登陆。 这是有用的定制用户的工做流以前让他们彻底登陆。 这多是有用的,迫使用户填写注册页面,改变密码,或者接受EULA以前让他们继续下去。
这部分执行登陆经过发行使用武士刀的“部分登陆”饼干饼干中间件的身份验证AuthenticationType的常数Constants.PartialSignInAuthenticationType。
部分的登陆显示全部相同的参数如上所述登陆(即为一个完整的。subject, name, claims, amr,idp)以及redirectPath。 的redirectPath表明了一个自定义web页面提供的托管应用程序,用户将被重定向到。 在用户的web页面subject和name声称能够用来识别用户(除了全部其余Claims表示)。 为了得到这些说法,页面必须使用武士刀验证中间件来验证Constants.PartialSignInAuthenticationType身份验证类型,或仅仅是执行在同一个饼干路径IdentityServer在web服务器。
一旦用户自定义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(错误)做为其参数。
请注意本文档是正在进行的工做。 随时添加新的内容。
若是您正在运行在IIS,您须要同步机键。 若是您正在运行IIS以外, 您须要使用武士刀的web农场兼容的数据保护。
不幸的是,刀不附带一个开箱即用的。 IdentityServer包括一个数据保护的基础上 X。 509证书(X509CertificateDataProtector),您能够设置的选项类。
若是你想终止SSL负载均衡器,有两个相关的设置选项:
确保签名证书部署到全部节点。
做用域的配置数据,客户和用户必须同步。
他们要么是静态的,你改变经过持续部署配置数据,或者你使用持久层 实体框架回购(MongoDB或社区的贡献)。
一些功能须要操做数据的共享数据库,即受权代码,参考令牌和刷新令牌。 若是你使用这些功能须要一个持久层。 你可使用咱们implemenation实体框架。
IdentityServer有一个简单的内置内存缓存。 这是有用的但不像它能够优化网络农场。 你能够插入本身的缓存实现ICache
支持实体框架IdentityServer来源这回购。
若是范围或客户数据须要从数据库加载(而不是使用内存配置),而后提供一个基于实体框架的实现IClientStore和IScopeStore服务。更多的信息。
另外,强烈建议操做数据(如受权码,刷新令牌,参考标记,和用户赞成)被保存在数据库中。 所以,咱们也有实体框架的实现IAuthorizationCodeStore, ITokenHandleStore, IRefreshTokenStore,IConsentStore服务。更多的信息
的ClientStore的EF-based实现吗IClientStore接口。 它能够单独使用的ScopeStore。
的ScopeStore的EF-based实现吗IScopeStore接口。 它能够单独使用的ClientStore。
使用的商店,他们须要注册。 上有扩展方法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);
大部分的操做数据已通过期。 极可能须要移除这个陈旧的数据。 能够承载IdentityServer之外的应用程序或数据库自己(经过各类机制)。 若是须要你执行这个清理应用程序代码,那么TokenCleanup类提供协助。 它接受一个EntityFrameworkServiceOptions和一个Int32时间间隔(以秒为单位)来配置陈旧的数据清理的频率。 它将异步链接到数据库,能够配置为:
var efConfig = new EntityFrameworkServiceOptions {
ConnectionString = connString,
//Schema = "foo"};
var cleanup = new TokenCleanup(efConfig, 10);cleanup.Start();
IdentityServer3加强,数据库模式极可能会发生变化。 的预期模式变化,建议(和预期)托管应用程序负责处理这些模式会随着时间而改变。
实体框架提供了迁移做为一个方法来处理模式变化和更新您的数据库与变化。
有三种不一样的DbContext派生类中包含的EF的实现。 它们是:
l ClientConfigurationDbContext
l ScopeConfigurationDbContext
l OperationalDbContext
这些须要,由于数据库上下文类(即在一个不一样的装配。Thinktecture.IdentityServer3.EntityFramework比托管应用程序)。
迁移必须为每一个数据库建立上下文类。 使迁移的全部数据库上下文类,可使用下面的命令从包管理器控制台:
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-Migration和Update-Database更新到新模式。 检查英孚文档为更多的细节。
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插件对检索的内置支持从一个内存中的服务依赖方。
看到在这里
的RelyingParty类模型依赖方:
ws - federation插件包含两个端点
这是主要的ws - federation端点的签字。
支持参数:
示例(可读性编码删除):
/wsfed?wa=wsignin1.0&wtrealm=rp1&whr=Google
返回元数据文档:
/wsfed/metadata
l OAuth2规范
l 混合流
l 注销后重定向
l 注销后自动重定向
l 斯科特·布雷迪:IdentityServer3独立实现pt。1
l 斯科特·布雷迪:IdentityServer3独立实现pt。2
l 斯科特·布雷迪:IdentityServer3独立实现pt。3
l 介绍OpenID链接,OAuth2 IdentityServer
l 布鲁克和多明尼克的身份和访问控制的现代Web应用程序和api车间
l 创建和确保一个RESTful api的多个客户端ASP。 净在PluralSight
l ElasticSearch / Kibana EventService
l 复述,缓存
l OpenID链接
l 谷歌
l 推特
l 微软帐户
l 脸谱网
l KentorIT认证服务——看到也这博客