tnblog
首页
视频
资源
登录

.net core 3.1 Identity Server4 (Implicit模式)

6086人阅读 2020/12/18 16:55 总访问:3660800 评论:0 收藏:0 手机
分类: Ids4

.netcore

.net core 3.1 Identity Server4 (Implicit模式)

Implicit 模式的理解


A.用户通过浏览器访问客户端,然后客户端跳转到授权服务器上。
B.用户输入用户和密码(授权信息)
C.当用户输入的用户和密码有效的话,将跳转回指定的页面(这里根据客户端传过去Url做返回),并且带有Access Token。
D.跳入指定的链接,对Access Token以及其他参数做存储数据的处理(如存储到local storage中)
E.存储完毕后,以前端脚本的形式跳回客户端
相对于Code来说:缺少了对客户端的验证,直接拿到了Access Token

创建客户端(AiDaSi.OcDemo.JavaScriptClient)


修改launchSettings.json文件

  1. {
  2. "profiles": {
  3. "AiDaSi.OcDemo.JavaScriptClient": {
  4. "commandName": "Project",
  5. "launchBrowser": true,
  6. "applicationUrl": "https://localhost:6001",
  7. "environmentVariables": {
  8. "ASPNETCORE_ENVIRONMENT": "Development"
  9. }
  10. }
  11. }
  12. }

安装依赖包Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation,用来Razor视图和Razor页面的汇编。

修改Startup.cs

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddControllersWithViews()
  4. .AddRazorRuntimeCompilation();
  5. }
  6. public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
  7. {
  8. if (env.IsDevelopment())
  9. {
  10. app.UseDeveloperExceptionPage();
  11. }
  12. app.UseStaticFiles();
  13. app.UseRouting();
  14. app.UseEndpoints(endpoints =>
  15. {
  16. endpoints.MapDefaultControllerRoute();
  17. });
  18. }

创建Controllers/HomeController.cswwwroot文件夹

  1. public class HomeController : Controller
  2. {
  3. public IActionResult Index()
  4. {
  5. return View();
  6. }
  7. }

Implicit Flow

接着我们来看看Implicit Flow的请求格式,格式如下,参数意义看下表

response_type 必需要的 必须包括id_token用于OpenID Connect登录。它还可能包含response_type token。使用token此处将允许您的应用立即从授权端点接收访问令牌,而无需再次向授权端点发出请求。如果使用tokenresponse_type,则scope参数必须包含一个范围,该范围指示要为其发行令牌的资源(例如,Microsoft Graph上的user.read)。它也可以code代替token提供授权码而包含在授权码流中使用。这种id_token + code响应有时称为混合流。
client_id 必需要的 页面分配给您的应用程序的应用程序(客户端)ID 。
redirect_uri 必需要的 应用程序的redirect_uri,您的应用程序可以在其中发送和接收身份验证响应。它必须与您在门户网站中注册的redirect_uris之一完全匹配,但必须使用url编码。
scope 必需要的 资源范围。
state 推荐要得 请求中包含的值也将在令牌响应中返回。它可以是您希望的任何内容的字符串。通常使用随机生成的唯一值来防止跨站点请求伪造攻击。状态还用于在身份验证请求发生之前在应用程序中对有关用户状态的信息进行编码,例如用户所在的页面或视图。
nonce 需要的 应用程序生成的请求中包含的值,该值将作为声明包含在生成的id_token中。然后,该应用可以验证该值以减轻令牌重放攻击。该值通常是一个随机的,唯一的字符串,可用于标识请求的来源。仅在请求id_token时才需要。

更多参数请参考:https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-implicit-grant-flow

我们来按照上面的请求格式进行模拟创建请求,添加客户端中Home/index.cshtml视图,内容如下。

  1. h1>Javascript Client</h1>
  2. <button type="button" onclick="signIn()">登录</button>
  3. <script src="~/SignIn.js" type="text/javascript"></script>

通过上一次的Code客户端模式做一次登录模拟请求,获取得到的地址如下:

可以知道它的回调链接是/connect/authorize/callback,添加一个SignIn.js的js到wwwroot中,仿照一个链接如下:

  1. // createState与createNonce随便填填就好了
  2. var createState = function () {
  3. return "createStateasdfasdfasdfasdfasdfasd";
  4. }
  5. var createNonce = function () {
  6. return "createNoncecreateNoncecreateNoncecreateNoncecreateNonce";
  7. }
  8. var signIn = function () {
  9. // 跳回到客户端的/Home/SignIn地址
  10. var redirectUri = "https://localhost:6001/Home/SignIn";
  11. var responseType = "id_token token";
  12. var scope = "openid ApiOne";
  13. var authUrl = "/connect/authorize/callback" +
  14. "?client_id=js_client" +
  15. "&redirect_uri=" + encodeURIComponent(redirectUri) +
  16. "&response_type=" + encodeURIComponent(responseType) +
  17. "&scope=" + encodeURIComponent(scope) +
  18. "&nonce=" + createNonce() +
  19. "&state=" + createState();
  20. var returnUrl = encodeURIComponent(authUrl);
  21. console.log(authUrl);
  22. console.log(returnUrl);
  23. // 我们在拼接好后访问
  24. window.location.href = "https://localhost:7200/IdentityCodeAuth/Login?ReturnUrl=" + returnUrl;
  25. }

接着我们访问试试..


接着我们在授权服务器上添加Implicit授权客户端

  1. new Client
  2. {
  3. ClientId = "js_client",
  4. // Implicit
  5. AllowedGrantTypes = GrantTypes.Implicit,
  6. //登录成功后,跳转的地址
  7. RedirectUris = { "https://localhost:6001/Home/SignIn" },
  8. AllowedScopes =
  9. {
  10. "ApiOne",
  11. IdentityServerConstants.StandardScopes.OpenId,
  12. },
  13. //允许浏览器访问令牌
  14. AllowAccessTokensViaBrowser = true,
  15. //作用范围
  16. RequireConsent = false
  17. }

好的我们登录来试试,我们发现我们并没有添加图中所对应的页面,单里面返回了许多值这些值当中就有我们需要的Access Token

在客户端中添加SignIn方法,并创建对应的视图。访问成功后完成D步骤。

  1. public IActionResult SignIn()
  2. {
  3. return View();
  4. }
  1. <h1>登录成功</h1>

为返回的页面添加按钮,创建sign-in-callback.js文件来解码其中的值并添加到LocalStorage中去。

  1. <h1>登录成功</h1>
  2. <button onclick="extractTokens(window.location.href)">Extract Tokens</button>
  3. <script src="~/sign-in-callback.js"></script>
  1. var extractTokens = function (callbackUrl) {
  2. var returnValue = callbackUrl.split('#')[1];
  3. var values = returnValue.split('&');
  4. for (var i = 0; i < values.length; i++) {
  5. var v = values[i];
  6. var kvPair = v.split('=');
  7. //将获取到的信息初入LocalStorage里面
  8. localStorage.setItem(kvPair[0], kvPair[1]);
  9. }
  10. }

此时我们获取到了我们所需要的一切

修改sign-in-callback.js,然后我们可以将跳回到首页中去

  1. var extractTokens = function (callbackUrl) {
  2. var returnValue = callbackUrl.split('#')[1];
  3. var values = returnValue.split('&');
  4. for (var i = 0; i < values.length; i++) {
  5. var v = values[i];
  6. var kvPair = v.split('=');
  7. //将获取到的信息初入LocalStorage里面
  8. localStorage.setItem(kvPair[0], kvPair[1]);
  9. }
  10. //再返回到首页中去
  11. window.location.href = '/home/index';
  12. }
  13. var _callbackUrl = window.location.href;
  14. extractTokens(_callbackUrl)

Oidc-Client 简介

oidc-client是一个JavaScript库,指在浏览器中运行。它为OIDC和OAuth2提供协议支持,以及用于用户会话和访问令牌管理的管理功能。
根据使用库的级别,可能要使用两个主要类:

1 .UserManager类为签约用户,注销,管理从OIDC提供程序返回的用户的声明,以及管理令牌从 OIDC/OAuth2 用户提供返回的接入更高级别的API。该UserManager是库的主要功能。

2 .OidcClient类提供的授权端点和在授权服务器结束会话端点原始 OIDC/OAuth2 用户协议的支持。它提供了基本的协议实现,并且由UserManager该类使用。仅在只希望协议支持而又没有UserManager该类的其他管理功能的情况下,才使用此类。

属性设置表

UserManager构造函数需要一个设置对象作为参数。设置具有以下属性:

authority string OIDC/OAuth2 提供程序的URL。
client_id string 在 OIDC/OAuth2 提供程序中注册的客户端应用程序的标识符。
redirect_uri string 您的客户端应用程序的重定向URI,以接收来自 OIDC/OAuth2 提供程序的响应。
response_type string, 默认为: 'id_token' OIDC/OAuth2 提供程序所需的响应类型。
scope string, 默认为: 'openid' 从 OIDC/OAuth2 提供程序请求的范围。

使用OIDC-Client.js登录

添加main.js文件到wwwroot中去

  1. var config = {
  2. authority: "https://localhost:7200/", // OIDC/OAuth2提供程序的URL。
  3. client_id: "js_client", // 在 OIDC/OAuth2 提供程序中注册的客户端应用程序的标识符。
  4. response_type: "id_token token", // 默认值'id_token' OIDC/OAuth2 提供程序所需的响应类型。 Type为Implicit时
  5. redirect_uri: "https://localhost:6001/Home/SignIn", // 您的客户端应用程序的重定向URI,以接收来自 OIDC/OAuth2 提供程序的响应。
  6. scope: 'ApiOne openid', // 从 OIDC/OAuth2 提供程序请求的范围。
  7. }
  8. var userManger = new Oidc.UserManager(config);
  9. var signIn = function () {
  10. userManger.signinRedirect();
  11. }

修改index.cshtml文件的内容

  1. <h1>Javascript Client</h1>
  2. <button type="button" onclick="signIn()">登录</button>
  3. <script src="https://cdn.bootcdn.net/ajax/libs/oidc-client/1.9.1/oidc-client.min.js"></script>
  4. <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.min.js"></script>
  5. <script src="~/main.js"></script>

在授权服务器中js_client客户端下面添加允许跨域的地址

  1. //跨域请求白名单
  2. AllowedCorsOrigins = { "https://localhost:6001" },

修改登录成功后修改回调页面SignIn.cshtml的内容

  1. <h1>登录成功</h1>
  2. <script src="https://cdn.bootcdn.net/ajax/libs/oidc-client/1.9.1/oidc-client.min.js"></script>
  3. <script>
  4. var userManager = new Oidc.UserManager();
  5. userManager.signinCallback().then(res => {
  6. console.log('处理已经完成,正在执行回调函数:', res);
  7. window.location.href = '/home/index';
  8. });
  9. </script>

然后运行,成功走完登录流程,并输出了我们想要的数据。里面有id_tokenaccess_token….

请求API(ApIDemo1)

在API Startup中添加跨域政策与服务

  1. //添加跨域服务政策
  2. services.AddCors(config => {
  3. config.AddPolicy("AllowAll",
  4. p => p.AllowAnyOrigin()
  5. .AllowAnyMethod()
  6. .AllowAnyHeader()
  7. );
  8. });
  1. //使用跨域的中间件
  2. app.UseCors("AllowAll");

main.js添加将token加入到请求对象中与对API接口访问的功能。

  1. // 判断用户是否登录
  2. userManger.getUser().then(user => {
  3. console.log("user:", user);
  4. if (user) {
  5. // 将token加入到axios请求对象中
  6. axios.defaults.headers.common["Authorization"] = "Bearer " + user.access_token;
  7. }
  8. });
  9. // 请求API接口
  10. var callApi = function () {
  11. axios.get("http://localhost:5280/WeatherForecast")
  12. .then(res => {
  13. console.log(res);
  14. });
  15. }

index.cshtml中,添加对接口的请求

  1. <div>
  2. <button type="button" onclick="callApi()">请求APIOne接口</button>
  3. </div>

启动接口项目

在登录后对接口进行访问,获取到接口信息

设置用户信息存储的地方

userStore用于为当前经过身份验证的用户保留用户的存储对象到localstorage,接下来我们为main.js中的configSignln.cshtml中实例UserManager对象时添加下面的代码。

  1. userStore: new Oidc.WebStorageStateStore({ store: window.localStorage })

刷新Token

在授权服务器中修改Config,设置如下

  1. new Client
  2. {
  3. ClientId = "js_client",
  4. // Implicit
  5. AllowedGrantTypes = GrantTypes.Implicit,
  6. //登录成功后,跳转的地址
  7. RedirectUris = { "https://localhost:6001/Home/SignIn" },
  8. //退出时跳转的地址
  9. PostLogoutRedirectUris = { "https://localhost:6001/Home/Index" },
  10. //跨域请求白名单
  11. AllowedCorsOrigins = { "https://localhost:6001" },
  12. AllowedScopes =
  13. {
  14. "ApiOne",
  15. IdentityServerConstants.StandardScopes.OpenId,
  16. },
  17. //访问令牌的生命周期为30秒钟
  18. AccessTokenLifetime = 30,
  19. //允许浏览器访问令牌
  20. AllowAccessTokensViaBrowser = true,
  21. //作用范围
  22. RequireConsent = false
  23. }

main.jsconfig中添加注销后的重定向地址

  1. post_logout_redirect_uri: "https://localhost:6001/Home/Index",

Access Token失效后,我们需要在js的客户端过滤器中进行刷新操作。在main.js中添加如下代码可达成自动刷新的效果。

  1. var refreshing = false;
  2. //输出拦截器
  3. axios.interceptors.response.use(
  4. function (response) {
  5. return response;
  6. },
  7. //当报错时刷新令牌
  8. function (error) {
  9. console.log(" axios error: ", error.response);
  10. let axiosConfig = error.response.config;
  11. // 如果状态码是401我们将会刷新令牌
  12. if (error.response.status === 401) {
  13. console.log(" axios error 401");
  14. // 如果已经刷新,请不要再提出其他需求
  15. if (!refreshing) {
  16. console.log("开始刷新");
  17. refreshing = true;
  18. // 刷新令牌方法
  19. return userManger.signinSilent().then(res => {
  20. console.log(res);
  21. // 更新请求Token与本地客户端的Token
  22. axios.defaults.headers.common['Authorization'] = "Bearer " + res.access_token;
  23. axiosConfig.headers['Authorization'] = "Bearer " + res.access_token;
  24. refreshing = false;
  25. // 并重试一下axios的请求
  26. return axios(axiosConfig);
  27. });
  28. }
  29. }
  30. // 带一个有拒绝原因的方法
  31. return Promise.reject(error);
  32. });


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价

ServiceStack.Redis操作Redis配置单例模式

我携漫天星辰以赠你,仍觉漫天星辰不如你。单利的应该是连接池而不应该是redis对象。如果每次操作都是一个redis对象是会有...

GIT中的PR模式

GIT中的Pull Request模式(简称PR)PR是开发者使用Github进行协作的利器。PR是协作者修改代码后或在原基础上增加新代码后向...

EF三种模式解析

万般皆下品,惟有编程高我希望你是为我而来如果我爱你,而你也正巧爱我。你头发乱了时候,我会笑笑地替你拨一拨,然后,手...

identity server4 的授权模式

授权模式OAuth2.0 定义了四种授权模式:Implicit:简化模式;直接通过浏览器的链接跳转申请令牌。Client Credentials:客户...

identity server4 四种授权模式

爱情哪有那么复杂,能让你开开心心笑得最甜的那个人就是对的人下面介绍4种模式安全性从低到高客户端模式客户端模式只对客户...

IdentityServer4实现OAuth2.0四种模式之授权码模式

授权码模式隐藏码模式最大不同是授权码模式不直接返回token,而是先返回一个授权码,然后再根据这个授权码去请求token。这...

也谈TDD,以及三层架构、设计模式、ORM……

想在园子里写点东西已经很久了,但一直没有落笔,还有些软文做推广,还要做奶爸带孩子,还要……好吧,我承认,真正的原因...

.netcore 3.1 MediatR:轻松实现命令查询职责分离模式(CQRS)

.netcore 3.1 MediatR:轻松实现命令查询职责分离模式(CQRS)[TOC] 中介者模式 用一个中介对象封装一系列的对象交...

.net core 3.1 Identity Server4 (ClientCredentials模式)

.net core 3.1 Identity Server4 (ClientCredentials模式)[TOC] ClientCredentials 模式的理解 在这之前我先问大家...

.net core 3.1 Identity Server4 (Password模式)

.net core 3.1 Identity Server4 (Password模式)[TOC] Password 模式的理解 当应用程序将用户的用户名和密码交换为...

.net core 3.1 Identity Server4 (Code模式)

.net core 3.1 Identity Server4 (Code模式)[TOC] Code 模式的理解 大致说一下,这种授权模式的意义。A. 用户通...

Go Map与工厂模式,在Go语言中实现Set

Go Map与工厂模式,在Go语言中实现Set[TOC] Map与工厂模式 Map 的 value 可以是一个方法与 Go 的 Dock type 接口方式一起...

.net core 3.1 Identity Server4 (Hybrid模式)

.net core 3.1 Identity Server4 (Hybrid模式)[TOC] Hybrid 模式的理解 Hybrid 模式相当于(Code模式+Impact模式),所...

.net core 3.1 Identity Server4 (自定义模式)

.net core 3.1 Identity Server4 (自定义模式)[TOC] IdentityServer4除了提供常规的几种授权模式外(AuthorizationCod...

策略设计模式需要的4大步骤

1:策略接口类: 是对策略, 算法的抽象. 定义了每个策略和算法必须有的算法和属性.2:策略实现类: 策略,算法的具体实现. 策...
这一世以无限游戏为使命!
排名
3
文章
317
粉丝
22
评论
14
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术