Open ID Connect(OIDC)在 ASP.NET Core中的应用
我们在《ASP.NET Core项目实战的课程》第一章里面给identity server4做了一个全面的介绍和示例的练习 ,这篇文章是根据大家对OIDC遇到的一些常见问题整理得出。
本文将涉及到以下几个话题:
什么是OpenId Connect (OIDC)
OIDC 对oAuth进行了哪些扩展?
Identity Server4提供的OIDC认证服务(服务端)
ASP.NET Core的权限体系中的OIDC认证框架(客户端)
什么是 OIDC
在了解OIDC之前,我们先看一个很常见的场景。假使我们现在有一个网站要集成微信或者新浪微博的登录,两者现在依然采用的是oAuth 2.0的协议来实现 。 关于微信和新浪微博的登录大家可以去看看它们的开发文档。
在我们的网站集成微博或者新浪微博的过程大致是分为五步:
准备工作:在微信/新浪微博开发平台注册一个应用,得到AppId和AppSecret
发起 oAauth2.0 中的 Authorization Code流程请求Code
根据Code再请求AccessToken(通常在我们应用的后端完成,用户不可见)
根据 AccessToken 访问微信/新浪微博的某一个API,来获取用户的信息
后置工作:根据用户信息来判断是否之前登录过?如果没有则创建一个用户并将这个用户作为当前用户登录(我们自己应用的登录逻辑,比如生成jwt),如果有了则用之前的用户登录。
中间第2到3的步骤为标准的oAuth2 授权码模式的流程,如果不理解的可以参考阮一峰所写的《理解oAuth2.0》一文。我们主要来看第4和5步,对于第三方应用要集成微博登录这个场景来说最重要的是我希望能快速拿到用户的一些基本信息(免去用户再次输入的麻烦)然后根据这些信息来生成一个我自己的用户跟微博的用户Id绑定(为的是下次你使用微博登录的时候我还能把你再找出来)。
oAuth在这里麻烦的地方是我还需要再请求一次API去获取用户数据,注意这个API和登录流程是不相干的,其实是属于微博开放平台丛多API中的一个,包括微信开放平台也是这样来实现。这里有个问题是前面的 2和3是oAuth2的标准化流程,而第4步却不是,但是大家都这么干(它是一个大家都默许的标准)
于是大家干脆就建立了一套标准协议并进行了一些优化,它叫OIDC
OIDC 建立在oAuth2.0协议之上,允许客户端(Clients)通过一个授权服务(Authorization Server)来完成对用户认证的过程,并且可以得到用户的一些基本信息包含在JWT中。
OIDC对oAuth进行了哪些扩展?
在oAuth2.0授权码模式的帮助下,我们拿到了用户信息。
以上没有认证的过程,只是给我们的应用授权访问一个API的权限,我们通过这个API去获取当前用户的信息,这些都是通过oAuth2的授权码模式完成的。 我们来看看oAuth2 授权码模式的流程:
第一步,我们向authorize endpoint请求code的时候所传递的response_type表示授权类型,原来只有固定值code
GET /connect/authorize?response_type=code&client_id=postman&state=xyz&scope=api1
&redirect_uri=http://localhost:5001/oauth2/callback
第二步,上面的请求执行完成之后会返回301跳转至我们传过去的redirect_uri并带上code
https://localhost:5001/oauth2/callback?code=835d584d4bc96d46ce49e27ebdbf272e40234d5f31097f63163f17da61fcd01c
&scope=api1
&state=111271607
第三步,用code换取access token
POST /connect/token?grant_type=authorization_code&code=835d584d4bc96d46ce49e27ebdbf272e40234d5f31097f63163f17da61fcd01c
&redirect_uri=http://localhost:5001/oauth2/callback
&client_id=postman
&client_secret=secret
通过这个POST我们就可以得到access_token
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjV",
"expires_in": 3600,
"token_type": "Bearer"
}
我们拿到access_token之后,再把access_token放到authorization头请求 api来获取用户的信息。在这里,这个api不是属于授权服务器提供的,而是属于资源服务器。
OIDC给oAuth2进行扩展之后就填补了这个空白,让我们可以授权它添加了以下两个内容:
- response_type 添加IdToken
- 添加userinfo endpoint,用idToken可以获取用户信息
OIDC对它进行了扩展,现在你有三个选择:code, id_token和 token,现在我们可以这样组合来使用。
"response_type" value | Flow |
---|---|
code | Authorization Code Flow |
id_token | Implicit Flow |
id_token token | Implicit Flow |
code id_token | Hybrid Flow |
code token | Hybrid Flow |
code id_token token | Hybrid Flow |
我们简单的来理解一下这三种模式:
Authorization Code Flow授权码模式:保留oAuth2下的授权模式不变response_type=code
Implicit Flow 隐式模式:在oAuth2下也有这个模式,主要用于客户端直接可以向授权服务器获取token,跳过中间获取code用code换accesstoken的这一步。在OIDC下,responsetype=token idtoken,也就是可以同时返回access_token和id_token。
Hybrid Flow 混合模式: 比较有典型的地方是从authorize endpoint 获取 code idtoken,这个时候id_token可以当成认证。而可以继续用code获取access_token去做授权,比隐式模式更安全。
再来详细看一下这三种模式的差异:
Property | Authorization Code Flow | Implicit Flow | Hybrid Flow |
---|---|---|---|
access token和id token都通过Authorization endpoint返回 | no | yes | no |
两个token都通过token end point 返回 | yes | no | no |
用户使用的端(浏览器或者手机)无法查看token | yes | no | no |
Client can be authenticated | yes | no | yes |
支持刷新token | yes | no | yes |
不需要后端参与 | no | yes | no |
我们来看一下通过Hybird如何获取 code、id_token、_以及access_token,然后再用id_token向userinfo endpoint请求用户信息。
第一步:获取code,
- response_type=code id_token
- scope=api1 openid profile 其中openid即为用户的唯一识别号
GET /connect/authorize?response_type=code id_token&client_id=postman&state=xyz&scope=api1 openid profile
&nonce=7362CAEA-9CA5-4B43-9BA3-34D7C303EBA7
&redirect_uri=http://localhost:5001/oauth2/callback
当我们使用OIDC的时候,我们请求里面多了一个nonce的参数,与state有异曲同工之妙。我们给它一个guid值即可。
第二步:我们的redirect_uri在接收的时候即可以拿到code 和 id_token
https://localhost:5001/oauth2/callback#
code=c5eaaaca8d4538f69f670a900d7a4fa1d1300b26ec67fba2f84129f0ab4ffa35
&id_token=eyJhbGciOiJSUzI1NiIsImtpZCI6IjVjMzA5ZGIwYTE2OGEwOTgGtpbj0GVXNnkKhGdrzA
&scope=openid%20profile%20api1&state=111271607
第三步:用code换access_token(这一步与oAuth2中的授权码模式一致)
第四步:用access_token向userinfo endpoint获取用户资料
Get http://localhost:5000/connect/userinfo
Authorization Bearer access_token
返回的用户信息
{
"name": "scott",
"family_name": "liu",
"sub": "5BE86359-073C-434B-AD2D-A3932222DABE"
}
以下是我们的流程示意图。
有人可能会注意到,在这里我们拿到的idtoken没有派上用场,我们的用户资料还是通过access_token从userinfo endpoint里拿的。这里有两个区别:
- userinfo endpoint是属于认证服务器实现的,并非资源服务器,有归属的区别
- id_token 是一个jwt,里面带有用户的唯一标识,我们在判断该用户已经存在的时候不需要再请求userinfo endpoint
下图是对id_token进行解析得到的信息:sub即subject_id(用户唯一标识 )
对jwt了解的同学知道它里面本身就可以存储用户的信息,那么id_token可以吗?答案当然是可以的,我们将在介绍完identity server4的集成之后最后来实现。
Identity Server4提供的OIDC认证服务
Identity Server4是asp.net core2.0实现的一套oAuth2 和OIDC框架,用它我们可以很快速的搭建一套自己的认证和授权服务。我们来看一下用它如何快速实现OIDC认证服务。
由于用户登录代码过多,完整代码可以加入ASP.NET Core QQ群 92436737获取。 此处仅展示配置核心代码。
过程
- 新建asp.net core web应用程序
- 添加identityserver4 nuget引用
- 依赖注入初始化
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetTestUsers());
- 中间件添加
app.UseIdentityServer();
- 配置
在测试的时候我们新建一个Config.cs来放一些配置信息
api resources
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "API Application"){
UserClaims = { "role", JwtClaimTypes.Role }
}
};
}
identity resources
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "API Application"){
UserClaims = { "role", JwtClaimTypes.Role }
}
};
}
clients
我们要讲的关键信息在这里,client有一个AllowGrantTypes它是一个string的集合。我们要写进去的值就是我们在上一节讲三种模式: Code,Implict和Hybird。因为这三种模式决定了我们的response_type可以请求哪几个值,所以这个地方一定不能写错。
IdentityServer4.Models.GrantTypes这个枚举给我们提供了一些选项,实际上是把oAuth的4种和OIDC的3种进行了组保。
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "postman", AllowedGrantTypes = GrantTypes.Hybird,
RedirectUris = { "https://localhost:5001/oauth2/callback" }, ClientSecrets =
{
new Secret("secret".Sha256())
}, AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
}, AllowOfflineAccess=true, },
};
}
users
public static List<TestUser> GetTestUsers()
{
return new List<TestUser> {
new TestUser {
SubjectId = "5BE86359-073C-434B-AD2D-A3932222DABE",
Username = "scott",
Password = "password",
Claims = new List<Claim> { new Claim(JwtClaimTypes.Name, "scott"),
new Claim(JwtClaimTypes.FamilyName, "liu"),
new Claim(JwtClaimTypes.Email, "scott@scottbrady91.com"),
new Claim(JwtClaimTypes.Role, "user"),
}
}
};
}
ASP.NET Core的权限体系中的OIDC认证框架
在Microsoft.AspNetCore.All nuget引用中包含了Microsoft.AspNetCore.Authentication.OpenIdConnect即asp.net core OIDC的客户端。我们需要在依赖注入中添加以下配置:
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "postman";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("api1");
options.Scope.Add("offline_access");
});
Authority即我们的用identity server4搭建的认证授权服务器,而其中的GetClaimsFromUserInfoEndpoint则会在拿到id_token之后自动向userinfo endpoint请求用户信息并放到asp.net core的User Identity下。
我们上面讲过,可以不需要请求userinfo endpoint, 直接将用户信息放到id_token中。
这样我们就不需要再向userinfo endpoint发起请求,从id_token中即可以获取到用户的信息。而有了identity server4的帮助,完成这一步只需要一句简单的配置即可:
new Client
{
ClientId = "postman", AlwaysIncludeUserClaimsInIdToken = true,
AllowOfflineAccess=true,
}
这样我们在拿到id_token之后,里即包含了我们的用户信息。
资料:
晓晨master的identity server4中文文档 http://www.cnblogs.com/stulzq/p/8119928.html李念辉身份认证核心:https://www.cnblogs.com/linianhui/archive/2017/05/30/openid-connect-core.html
OIDC协议: http://openid.net/specs/openid-connect-discovery-1_0.html
Jesse腾飞的asp.net core项目实战第一章identity server4准备 http://video.jessetalk.cn/course/5
Open ID Connect(OIDC)在 ASP.NET Core中的应用的更多相关文章
- 如何在ASP.NET Core中应用Entity Framework
注:本文提到的代码示例下载地址> How to using Entity Framework DB first in ASP.NET Core 如何在ASP.NET Core中应用Entity ...
- [译]在Asp.Net Core 中使用外部登陆(google、微博...)
原文出自Rui Figueiredo的博文<External Login Providers in ASP.NET Core> 摘要:本文主要介绍了使用外部登陆提供程序登陆的流程,以及身份 ...
- Asp.net Core中使用Redis 来保存Session, 读取配置文件
今天 无意看到Asp.net Core中使用Session ,首先要使用Session就必须添加Microsoft.AspNetCore.Session包,默认Session是只能存去字节,所以如果你 ...
- C#调用接口注意要点 socket,模拟服务器、客户端通信 在ASP.NET Core中构建路由的5种方法
C#调用接口注意要点 在用C#调用接口的时候,遇到需要通过调用登录接口才能调用其他的接口,因为在其他的接口需要在登录的状态下保存Cookie值才能有权限调用, 所以首先需要通过调用登录接口来保存c ...
- 【译】在Asp.Net Core 中使用外部登陆(google、微博...)
原文出自Rui Figueiredo的博文<External Login Providers in ASP.NET Core> (本文很长) 摘要:本文主要介绍了使用外部登陆提供程序登陆的 ...
- ASP.NET Core 中的实时框架 SingalR
目录 SignalR 是什么? 在 ASP.NET Core 中使用 SignalR 权限验证 横向扩展 源代码 参考 SignalR 是什么? ASP.NET Core SignalR 是一个开源的 ...
- 从零搭建一个IdentityServer——聊聊Asp.net core中的身份验证与授权
OpenIDConnect是一个身份验证服务,而Oauth2.0是一个授权框架,在前面几篇文章里通过IdentityServer4实现了基于Oauth2.0的客户端证书(Client_Credenti ...
- 使用Redis Stream来做消息队列和在Asp.Net Core中的实现
写在前面 我一直以来使用redis的时候,很多低烈度需求(并发要求不是很高)需要用到消息队列的时候,在项目本身已经使用了Redis的情况下都想直接用Redis来做消息队列,而不想引入新的服务,kafk ...
- ASP.NET Core 中文文档 第二章 指南(4.6)Controller 方法与视图
原文:Controller methods and views 作者:Rick Anderson 翻译:谢炀(Kiler) 校对:孟帅洋(书缘) .张仁建(第二年.夏) .许登洋(Seay) .姚阿勇 ...
随机推荐
- Java公开课-04.异常
一,异常的概念 程序在运行时,发生了我们没有预测的结果,它阻止了程序按照我们预期效果执行 二,怎么保证我们的程序在发生异常以后 ,代码继续执行? 异常处理机制 在程序发生异常以后,还能按照我们事先设定 ...
- sql server 高可用日志传送
一. 日志传送概述 SQL Server使用日志传送,可以自动将主服务器的事务日志备份发送到一个或多个辅助数据库上.可选的监视服务器,记录备份和还原操作的历史记录及状态. 优点 提供灾难恢复解决方案 ...
- Kali Linux图形界面与命令行界面的切换
前言: 有时候为了节约系统资源,使用命令行界面能够让Linux系统的运行更加流畅,处理任务的速度也更加快.现在的Kali安装完成后默认是开机就启动图形化界面.本文将介绍通过编辑Kali启动引导文件的方 ...
- Ames房价预测特征工程
最近学人工智能,讲到了Kaggle上的一个竞赛任务,Ames房价预测.本文将描述一下数据预处理和特征工程所进行的操作,具体代码Click Me. 原始数据集共有特征81个,数值型特征38个,非数值型特 ...
- Android 实战美女拼图游戏 你能坚持到第几关
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40595385,本文出自:[张鸿洋的博客] 1.概述 继2048之后,今天给大家带 ...
- 【Never Stop】联赛集训记录
始于10/01/2017. Day I: T2图论,没想到.T3谜一样DP(是从来没意识到还可以这样). rank10. 下午刷了点题,CDQ也只打出一个板子,感觉自己不在状态? ========== ...
- vue iview UPload,但文件上传是,clearFiles的使用方法
<template> <div> <button @click="clearUploadedImage">重新上传</button> ...
- 【SAP业务模式】之STO(一):业务背景和前台操作
所谓STO即两个关联公司之间的库存转储交易,一家公司发出采购订单向另一家公司做采购,然后在做发货.如此之后,两家公司有相应应收应付的票据,以及开票和发票校验等动作. STO分为一步法与两步法,因为一步 ...
- 文本离散表示(三):TF-IDF结合n-gram进行关键词提取和文本相似度分析
这是文本离散表示的第二篇实战文章,要做的是运用TF-IDF算法结合n-gram,求几篇文档的TF-IDF矩阵,然后提取出各篇文档的关键词,并计算各篇文档之间的余弦距离,分析其相似度. TF-IDF与n ...
- TensorFlow之DNN(二):全连接神经网络的加速技巧(Xavier初始化、Adam、Batch Norm、学习率衰减与梯度截断)
在上一篇博客<TensorFlow之DNN(一):构建“裸机版”全连接神经网络>中,我整理了一个用TensorFlow实现的简单全连接神经网络模型,没有运用加速技巧(小批量梯度下降不算哦) ...