IdentityServer4 中文文档 -11- (快速入门)添加基于 OpenID Connect 的用户认证


原文:http://docs.identityserver.io/en/release/quickstarts/3_interactive_login.html

目 录

上一篇:IdentityServer4 中文文档 -10- (快速入门)使用密码保护API

下一篇:IdentityServer4 中文文档 -12- (快速入门)添加外部认证支持

在这个快速启动中,我们希望通过OpenID Connect协议向我们的 IdentityServer 添加对交互式用户身份验证的支持。

完成之后,我们将创建一个使用 IdentityServer 进行身份认证的 MVC 应用程序。

添加 UI(用户界面)

IdentityServer 内置了 OpenID Connect 需要的所有协议支持。你需要提供必需的 UI 部分,包括 登录、注销、授权确认以及错误页。

因为在每个 IdentityServer 的实现中,视觉、感觉以及实际工作流可能总是有所不同的,所以我们提供了一套基于 MVC 的样例 UI,你可以将其作为启动点来使用。

这套 UI 可以在 快速入门仓库 找到。你还可以克隆或下载这个仓库,将其中的控制器、视图、模型以及 CSS 放到你的 Web 应用程序中。

你还可以在你的 Web 应用程序中以命令行的方式运行以下命令来自动下载:

iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1'))

查看 自述文件 以了解更多 快速入门UI 相关的信息。

注意: UI 仓库的 release 分支拥有与最新发布的稳定版相匹配的 UI。dev 分支则与 IdentityServer4 的当前开发构建相符。如果你想要寻找指定版本的 UI,请查看相应的标签。

花一些时间去查阅控制器和模型,你越是了解他们,将来要修改他们就越简单。大部分代码都以“功能目录”的样式放在 “Quickstart” 文件夹下,如果这种样式不适合你,那就按照你想要的方式随意组织代码。

创建一个 MVC 客户端

接下来你将向解决方案添加一个 MVC 应用程序,可以使用 ASP.NET Core "Web 应用程序" 模板来实现。 将应用程序配置为使用 5002 端口(可以查看概览部分以了解如何配置)。

为了能向 MVC 应用程序添加 OpenID Connect 认证支持,请添加如下 NuGet 程序包:

  • Microsoft.AspNetCore.Authentication.Cookies
  • Microsoft.AspNetCore.Authentication.OpenIdConnect

然后添加这两个中间件到你的管道中 —— Cookies 对应的中间件很简单:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme="Cookies"
});

OpenID Connect 中间件需要稍微多一些配置。将它指向 Identity Server,指定一个客户端 ID 并且告诉它哪个中间件将会负责本地登陆(也就是 cookies 中间件)。此外,我们关闭了 JWT 身份信息类型映射,这样就允许 well-known 身份信息(比如,“sub” 和 “idp”) 无干扰地流过。这个身份信息类型映射的 “清理” 必须在调用 UseOpenIdConnectAuthentication() 之前完成:

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
AuthenticationScheme = "oidc",
SignInScheme = "Cookies",
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
ClientId = "mvc",
SaveTokens = true
});

两个中间件都应该在 MVC 之前添加到管道。

下一个步骤是触发认证握手,为此打开 home 控制器并添加 [Authorize] 到其中一个 action 上。另外,修改 action 对应的视图以显示用户的身份信息,比如:

<dl>
@foreach (var claim in User.Claims)
{
<dt>@claim.Type</dt>
<dd>@claim.Value</dd>
}
</dl>

现在,如果你使用浏览器导航到上述控制器,一个Mvc客户端将视图重定向到 IdentityServer - 这会导致错误,因为 MVC 客户端还没有注册(在 IdentityServer 上定义)呢。

添加 OpenID Connect 身份 Scopes 支持

与 OAuth 2.0 相似,OpenID Connect 也使用 scopes 这个概念。再一次说明,Scopes 表示你想要保护的和客户端想要访问的事物。在与 OAuth 相比,OIDC(OpenID Connect) 中的 scopes 不仅代表 API,还代表了诸如 用户id、用户名 或 邮箱地址等身份数据。

通过(在 Config.cs 中)添加新的帮助器来创建 IdentityResource 对象的集合,可以添加对标准 openid(subject id,这里指的是用户id)和 profile(姓氏,名称 等等)等 scopes 的支持:

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

注意:所有标准的 Scopes 和他们对应的 身份信息 都可以在 OpenID Connect 规范 中找到。

接下来在 Startup.cs 中你要将这些身份资源添加到你的 IdentityServer 配置。在你调用 AddIdentityServer() 的地方使用 AddInMemoryIdentityResources 扩展方法即可:

public void ConfigureServices(IServiceCollection services)
{
// 使用内存存储,密钥,客户端和资源来配置身份服务器。
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetUsers())
.AddInMemoryIdentityResources(Config.GetIdentityResources());
}

为 OIDC 隐式流添加客户端定义

最后一个步骤是为 IdentityServer 添加一个新的客户端。

目前,我们添加的基于 OIDC 的客户端与 OAuth 2.0 客户端非常相似。但是由于 OIDC 中的流总是交互式的,所以我们需要添加一些重定向 URL 到我们的配置中。

添加以下代码到你的客户端配置中:

public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
// 省略的客户端... // OIDC 隐式流客户端(MVC)
new Client
{
ClientId = "mvc",
ClientName = "Mvc 客户端",
AllowedGrantTypes = GrantTypes.Implicit,
// 登录后重定向到的地址
RedirectUris = { "http://localhost:5002/signin-oidc" },
// 注销后重定向到的地址
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
};
}

测试 MVC 客户端

现在,对于新的 MVC 客户端,一切都准备好了。

将浏览器导航到受保护的 控制器 action 以触发认证握手。你应该能看到客户端将你重定向到了 IdentityServer 的登录页。

登录成功后,用户将在授权确认页中被呈现出来。在这里用户可以决定他是否想要发布他的身份信息给客户端应用程序。

注意: 授权确认页可以通过客户端定义对象的 RequireConsent 属性被关闭(以每个客户端为单位)。

最终浏览器将被重定向回客户端应用程序,即展示用户的身份信息。

注意:在开发期间你有时候可能会看到 无法验证令牌 的异常信息。这是因为实际上签名密钥材料是凭空产生的,并且在只内存中驻留。这个异常在 客户端 与 IdentityServer 不同步时就会发生。简单地重复客户端上的操作,等到下一次元数据被捕获时,一切都会再次正常工作的。

添加注销

最后的最后,是给 MVC 客户端添加 注销功能。

通过 IdentityServer 这样的服务进行身份认证,单单清除本地应用程序的 Cookies 是不够的。你还需要往返一次 IdentityServer 来清理集中式单点登录会话。

具体的协议步骤都在 OpenID Connect 中间件中实现了,简单地添加以下代码到某个控制器中就可以用来触发注销:

public async Task Logout()
{
await HttpContext.Authentication.SignOutAsync("Cookies");
await HttpContext.Authentication.SignOutAsync("oidc");
}

进一步实验

如前面所说,OpenID Connect 中间件默认会请求 profile scope。这个 scope 还包含了用户名或个人主页等身份信息。

让我们将这些身份信息添加到用户定义里面,这样的话 IdentityServer 就可以把它们放到身份令牌中了:


public static List<TestUser> GetUsers()
{
return new List<TestUser>()
{
new TestUser
{
SubjectId="1",
Username="爱丽丝",
Password="password", Claims = new []
{
new Claim("name", "爱丽丝"),
new Claim("website", "https://alice.com")
}
},
new TestUser
{
SubjectId="2",
Username="博德",
Password="password", Claims = new []
{
new Claim("name", "博德"),
new Claim("website", "https://bob.com")
}
}
};
}

下一次你认证的时候,你的身份信息页将会显示额外的身份信息。

请随意添加更多的身份信息 - 还有更多的 scopes。OpenID Connect 中间件上的 Scope 属性是你用来配置哪些 Scopes 将在认证期间被发送到 IdentityServer 的地方。

值得注意的是,对令牌中身份信息的遍历是一个扩展点 - IProfileService。因为我们正在使用 AddTestUser,所以默认使用的是 TestUserProfileService。你可以检出这里的源代码来查看它的工作原理。

目 录

上一篇:IdentityServer4 中文文档 -10- (快速入门)使用密码保护API

下一篇:IdentityServer4 中文文档 -12- (快速入门)添加外部认证支持

IdentityServer4 中文文档 -11- (快速入门)添加基于 OpenID Connect 的用户认证的更多相关文章

  1. IdentityServer4 中文文档 -15- (快速入门)添加 JavaScript 客户端

    IdentityServer4 中文文档 -15- (快速入门)添加 JavaScript 客户端 原文:http://docs.identityserver.io/en/release/quicks ...

  2. IdentityServer4 中文文档 -13- (快速入门)切换到混合流并添加 API 访问

    IdentityServer4 中文文档 -13- (快速入门)切换到混合流并添加 API 访问 原文:http://docs.identityserver.io/en/release/quickst ...

  3. IdentityServer4 中文文档 -12- (快速入门)添加外部认证支持

    IdentityServer4 中文文档 -12- (快速入门)添加外部认证支持 原文:http://docs.identityserver.io/en/release/quickstarts/4_e ...

  4. IdentityServer4 中文文档 -16- (快速入门)使用 EntityFramework Core 存储配置数据

    IdentityServer4 中文文档 -16- (快速入门)使用 EntityFramework Core 存储配置数据 原文:http://docs.identityserver.io/en/r ...

  5. IdentityServer4 中文文档 -14- (快速入门)使用 ASP.NET Core Identity

    IdentityServer4 中文文档 -14- (快速入门)使用 ASP.NET Core Identity 原文:http://docs.identityserver.io/en/release ...

  6. IdentityServer4 中文文档 -8- (快速入门)设置和概览

    IdentityServer4 中文文档 -8- (快速入门)设置和概览 原文:http://docs.identityserver.io/en/release/quickstarts/0_overv ...

  7. IdentityServer4 中文文档 -9- (快速入门)使用客户端凭证保护API

    IdentityServer4 中文文档 -9- (快速入门)使用客户端凭证保护API 原文:http://docs.identityserver.io/en/release/quickstarts/ ...

  8. IdentityServer4 中文文档 -10- (快速入门)使用密码保护API

    IdentityServer4 中文文档 -10- (快速入门)使用密码保护API 原文:http://docs.identityserver.io/en/release/quickstarts/2_ ...

  9. IdentityServer4 中文文档 -7- (简介)贡献

    IdentityServer4 中文文档 -7- (简介)贡献 原文:http://docs.identityserver.io/en/release/intro/contributing.html ...

随机推荐

  1. Excel列A、B、C、D----与列序号的转换

    public static class ExcelConvert { public static int ToExcelIndex(this string columnName) { if (!Reg ...

  2. 基于fpga的vga学习(2)

    本次学习主要向配合basys2实行. 上次学习vga的rgb三个output都是1位的,但是我看了basys2的rgb分别是332位,这里让我卡顿了很久, 之后通过查资料才知道,rgb的不同大小表示的 ...

  3. 6-使用requests库封装类处理get/post请求

    1.request安装 1)pip安装,直接pip install requests 2)下载离线包安装,加压后,命令行进入路径,执行python setup.py install 2.创建工程 注意 ...

  4. wxPyhon 的控件(摘抄)

    一.静态文本控件 wx.StaticText(parent, id, label, pos=wx.DefaultPosition,    size=wx.DefaultSize, style=0, n ...

  5. Vue实现懒加载的基本思路

    懒加载是前端开发者的基本功之一.实现懒加载肯定是要直接操作DOM的,这个没得跑,但我们可以想办法让流程尽可能优雅些. 基本结构 父组件是列表容器,子组件是列表中的项,如卡片.帖子等,承载图片的DOM对 ...

  6. 前端开发掌握nginx常用功能之server&location匹配规则

    nginx主要是公司运维同学必须掌握的知识,涉及到反向代理.负载均衡等服务器配置.前端开发尤其是纯前端开发来说对nginx接触的并不多,但是在一些情况下,nginx还是需要前端自己来搞:例如我们公司的 ...

  7. App设计:消息推送和界面路由跳转

    概要 app消息推送.显示通知栏,点击跳转页面是很一般的功能了,下面以个推为例演示push集成,消息处理模块及app内部路由模块的简单设计. 推送 推送sdk集成 集成sdk步骤根据文档一步步做就行了 ...

  8. ProgressBar 进度条开源项目总结

    在Android开发中,我们不免会遇到进度条展示的需求,以下是本人之前star的开源项目,供大家参考: 一.ArcProgressBar 开源项目地址:https://github.com/zenoT ...

  9. Javascript高级编程学习笔记(25)—— 函数表达式(3)模仿块级作用域

    昨天写了闭包 今天就来聊聊块级作用域的事情 在绝大多数编程语言中,都有块级作用域这个概念 什么是块级作用域呢? 前面我们在刚开始讲的时候说过,JS中的大括号(不在赋值运算符的后面)表示代码块 块级作用 ...

  10. 第81节:Java中的数组

    第81节:Java中的数组 本节介绍数组的基本概念,数据就是一种数据结构,可以用来存储多个数据,每个数组中可以存放相同类型的数据.比如,在学校,我们是一个班,这里的班级中每个同学都是这个班级数组中的元 ...