Identity Server 4使用OpenID Connect添加用户身份验证(三)

一、说明

基于上一篇文章中的代码进行继续延伸,只需要小小的改动即可,不明白的地方可以先看看本人上一篇文章及源码Identity Server 4资源拥有者密码认证控制访问API(二)

二、添加UI

官方GitHub:https://github.com/IdentityServer/IdentityServer4.Quickstart.UI

OpenID Connect 所需的所有协议支持都已内置到 IdentityServer 中。您需要为提供必要的UI部件:登录,注销,同意授权和错误页面。

根据业务场景的不同对 IdentityServer 的实现也有所不同,但我们提供了一个基于 MVC 的示例UI,您可以将其用作起步。

可以在快速入门UI仓库中找到此UI。 您可以克隆或下载此repo,并将Controller,View,Model和CSS放入IdentityServer Web 应用程序中。

或者,您可以使用.NET CLI(从 QuickStartIdentityServer4 文件夹中运行命令):

dotnet new -i identityserver4.templates
dotnet new is4ui

添加 MVC UI 后,您还需要在 DI 系统和管道中启用 MVC。 当您查看Startup.cs时,您将在 ConfigureServices 和 Configure 方法中找到有关如何启用MVC的注释

三、运行QuickStartIdentityServer4项目

 Identity Server 4使用OpenID Connect添加用户身份验证(三)

四、环境配置

一、QuickStartIdentityServer4项目中Config文件增加配置

// Clients集合中增加 基于OIDC客户端配置
            new Client
            {
               ClientId="sample_mvc_client",
               ClientName="Sample MVC Client",
               ClientSecrets=
                {
                    new Secret("sample_client_secret".Sha256())
                },
               AllowedGrantTypes=GrantTypes.Code,
               RedirectUris={ "http://localhost:4001/signin-oidc"},  // 登录成功之后的回调地址
               PostLogoutRedirectUris={ "http://localhost:4001/signout-callback-oidc" }, // 注销/登出之后的回调地址
               AllowedScopes={
                 IdentityServerConstants.StandardScopes.OpenId,
                 IdentityServerConstants.StandardScopes.Profile,
                "sample_api"  // 用于oidc认证成功之后访问项目API的范围api接口
                },
               RequireConsent=true // 是否需要用户同步,当用户登录的时候需要用户进行是否同意
            }
// 基于OIDC协议
        public static IEnumerable IdentityResources => new List
        {
          new IdentityResources.OpenId(),
          new IdentityResources.Profile()
        };

        // 基于OIDC添加测试用户
        public static List Users => new List() {

          new TestUser()
          {
              SubjectId="1",
              Username="admin",
              Password="123456777"
          }
        };

二、新增web项目Sample.MvcClient ,端口号4001 NuGet:Microsoft.AspNetCore.Authentication.OpenIdConnect

1、增加SameSiteCookiesServiceCollectionExtensions.cs扩展类,该类主要是为了解决认证成功,页面跳转异常问题

public static class SameSiteCookiesServiceCollectionExtensions
    {
        ///
        /// -1 defines the unspecified value, which tells ASPNET Core to NOT
        /// send the SameSite attribute. With ASPNET Core 3.1 the
        ///  enum will have a definition for
        /// Unspecified.

        ///
        private const SameSiteMode Unspecified = (SameSiteMode)(-1);

        ///
        /// Configures a cookie policy to properly set the SameSite attribute
        /// for Browsers that handle unknown values as Strict. Ensure that you
        /// add the
        /// into the pipeline before sending any cookies!

        ///
        ///
        /// Minimum ASPNET Core Version required for this code:
        ///   - 2.1.14
        ///   - 2.2.8
        ///   - 3.0.1
        ///   - 3.1.0-preview1
        /// Starting with version 80 of Chrome (to be released in February 2020)
        /// cookies with NO SameSite attribute are treated as SameSite=Lax.

        /// In order to always get the cookies send they need to be set to
        /// SameSite=None. But since the current standard only defines Lax and
        /// Strict as valid values there are some browsers that treat invalid
        /// values as SameSite=Strict. We therefore need to check the browser
        /// and either send SameSite=None or prevent the sending of SameSite=None.

        /// Relevant links:
        /// - https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-4.1
        /// - https://tools.ietf.org/html/draft-west-cookie-incrementalism-00
        /// - https://www.chromium.org/updates/same-site
        /// - https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
        /// - https://bugs.webkit.org/show_bug.cgi?id=198181
        ///
        /// The service collection to register  into.

        /// The modified .
        public static IServiceCollection ConfigureNonBreakingSameSiteCookies(this IServiceCollection services)
        {
            services.Configure(options =>
            {
                options.MinimumSameSitePolicy = Unspecified;
                options.OnAppendCookie = cookieContext =>
                   CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
                options.OnDeleteCookie = cookieContext =>
                   CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
            });

            return services;
        }

        private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
        {
            if (options.SameSite == SameSiteMode.None)
            {
                var userAgent = httpContext.Request.Headers["User-Agent"].ToString();

                if (DisallowsSameSiteNone(userAgent))
                {
                    options.SameSite = Unspecified;
                }
                else
                {
                    options.SameSite = SameSiteMode.Lax;  // 增加这句
                }
            }
        }

        ///
        /// Checks if the UserAgent is known to interpret an unknown value as Strict.

        /// For those the  property should be
        /// set to .
        ///
        ///
        /// This code is taken from Microsoft:
        /// https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
        ///
        /// The user agent string to check.

        /// Whether the specified user agent (browser) accepts SameSite=None or not.

        private static bool DisallowsSameSiteNone(string userAgent)
        {
            // Cover all iOS based browsers here. This includes:
            //   - Safari on iOS 12 for iPhone, iPod Touch, iPad
            //   - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
            //   - Chrome on iOS 12 for iPhone, iPod Touch, iPad
            // All of which are broken by SameSite=None, because they use the
            // iOS networking stack.

            // Notes from Thinktecture:
            // Regarding https://caniuse.com/#search=samesite iOS versions lower
            // than 12 are not supporting SameSite at all. Starting with version 13
            // unknown values are NOT treated as strict anymore. Therefore we only
            // need to check version 12.

            if (userAgent.Contains("CPU iPhone OS 12")
               || userAgent.Contains("iPad; CPU OS 12"))
            {
                return true;
            }

            // Cover Mac OS X based browsers that use the Mac OS networking stack.

            // This includes:
            //   - Safari on Mac OS X.

            // This does not include:
            //   - Chrome on Mac OS X
            // because they do not use the Mac OS networking stack.

            // Notes from Thinktecture:
            // Regarding https://caniuse.com/#search=samesite MacOS X versions lower
            // than 10.14 are not supporting SameSite at all. Starting with version
            // 10.15 unknown values are NOT treated as strict anymore. Therefore we
            // only need to check version 10.14.

            if (userAgent.Contains("Safari")
               && userAgent.Contains("Macintosh; Intel Mac OS X 10_14")
               && userAgent.Contains("Version/"))
            {
                return true;
            }

            // Cover Chrome 50-69, because some versions are broken by SameSite=None
            // and none in this range require it.

            // Note: this covers some pre-Chromium Edge versions,
            // but pre-Chromium Edge does not require SameSite=None.

            // Notes from Thinktecture:
            // We can not validate this assumption, but we trust Microsofts
            // evaluation. And overall not sending a SameSite value equals to the same
            // behavior as SameSite=None for these old versions anyways.

            if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
            {
                return true;
            }

            return false;
        }
    }

2、Startup配置

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            JwtSecurityTokenHandler.DefaultMapInboundClaims=false;
            services.AddAuthentication(options => {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
                //options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
             .AddCookie("Cookies")
             .AddOpenIdConnect("oidc", options => {
                 options.Authority = "http://localhost:5001";
                 options.ClientId = "sample_mvc_client";
                 options.ClientSecret = "sample_client_secret";
                 options.ResponseType = "code"; // 隐式授权时不用此段代码
                 options.SaveTokens=true;
                 options.Scope.Add("sample_api"); // 授权成功之后,如项目中无需访问基于范围认证api可不用此段代码
                 options.RequireHttpsMetadata = false; // 不采用https回调
             });

            services.ConfigureNonBreakingSameSiteCookies();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();

            app.UseRouting();

            // 使用cookie
            app.UseCookiePolicy();
            // 添加认证中间件
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }

3、控制器增加如下方法

///
        /// 登出
        ///
        ///
        public IActionResult LogOut()
        {
            return SignOut("Cookies","oidc");
        }

        ///
        /// 模拟请求api
        ///
        ///
        public async Task CallApi()
        {
            // 获取访问令牌
            var accessToken = await HttpContext.GetTokenAsync("access_token");
            // 创建HTTP客户端
            var client = new HttpClient();
            // 设置授权请求头
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            // 请求API
            var content = await client.GetStringAsync("http://localhost:5000/IdentityServer");
            // 转换api返回结果
            ViewBag.Josn = JArray.Parse(content).ToString();
            return View();
        }

        [Authorize]
        public IActionResult Privacy()
        {
            return View();
        }

4、Privacy.cshtml页面配置

'@Url.Action("LogOut")'>登出    '@Url.Action("CallApi")'>模拟请求api

    用户信息
    @foreach (var claim in User.Claims)
    {
        @claim.Type
        @claim.Value
    }

    认证信息
    @foreach (var prop in (await Context.AuthenticateAsync()).Properties.Items)
    {
        @prop.Key
        @prop.Value
    }

五、项目运行效果

1、同时启动API、QuickStartIdentityServer4、Sample.MvcClient

 Identity Server 4使用OpenID Connect添加用户身份验证(三)

 Identity Server 4使用OpenID Connect添加用户身份验证(三)

 Identity Server 4使用OpenID Connect添加用户身份验证(三)

 Identity Server 4使用OpenID Connect添加用户身份验证(三)

2、登出

 Identity Server 4使用OpenID Connect添加用户身份验证(三)

 Identity Server 4使用OpenID Connect添加用户身份验证(三)

3、模拟请求api

 Identity Server 4使用OpenID Connect添加用户身份验证(三)

 Identity Server 4使用OpenID Connect添加用户身份验证(三)

Original: https://www.cnblogs.com/sportsky/p/16468427.html
Author: SportSky
Title: Identity Server 4使用OpenID Connect添加用户身份验证(三)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/608896/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • OpenSSL测试-随机数

    任务详情 在openEuler(推荐)或Ubuntu或Windows(不推荐)中完成下面任务 使用OpenSSL定义一个私有函数 static int getRandom(char…

    Linux 2023年6月8日
    0102
  • RPA供应链管制单修改机器人

    bash;gutter:true;背景:供应链环节中,研发物料时而因为市场缺货等原因无法采购,资材部需登入系统修改物料管制单。操作流程:登录PDM系统中读取数据、登录ERP系统中更…

    Linux 2023年6月7日
    0111
  • 基于Redis实现分布式锁

    背景在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等。大部分的解决方案是基于DB实现的,Redis为单进程单线程模式,采用队列模式将并发访问变成…

    Linux 2023年5月28日
    0109
  • .NET Core 3.0, 发布将于今晚开始!

    期待已久的.NET Core 3.0即将发布! .NET Core 3.0在.NET Conf上发布。大约还有9个多小时后,.NET Conf开始启动。 第1天-9月23日 9:0…

    Linux 2023年6月7日
    086
  • 没学习的恐惧

    已经三个月没有接触新知识,每次上线之后就有一些bug,觉得自己作为一个点点点的测试很失败。我很迷茫,我都不知道自己一天是如何过的,反正就觉得时间过的很快,而且发现什么事都没做一天就…

    Linux 2023年6月8日
    095
  • 【原创】Linux虚拟化KVM-Qemu分析(七)之timer虚拟化

    背景 Read the fucking source code! –By 鲁迅 A picture is worth a thousand words. –…

    Linux 2023年6月8日
    0109
  • Linux vim退出命令

    :w – 保存文件,不退出 vim:w file -将修改另外保存到 file 中,不退出 vim:w! -强制保存,不退出 vim:wq -保存文件,退出 vim:w…

    Linux 2023年6月13日
    093
  • [Git系列] Git 基本概念

    版本控制系统 版本控制系统是一种帮助软件开发者实现团队合作和历史版本维护的软件,一个版本控制系统应具备以下列出的这几个基本功能: 允许开发者并发工作; 不允许一个开发者覆写另一个开…

    Linux 2023年6月14日
    0105
  • 搭建Redis三主三从集群

    Redis三主三从集群规划 10.0.128.19 使用端口 7000 700110.0.128.22 使用端口 7002 700310.0.128.23 使用端口 7004 70…

    Linux 2023年6月8日
    0111
  • 最小化安装killall不可用

    最小化安装killall不可用 最小化安装 Centos7.4后,发现killall命令不可用使用了以下命令,查看软件包名: yum search killall 查找后发现应使用…

    Linux 2023年6月13日
    0104
  • @Aspect

    AOP是指在程序运行期间动态地将某段代码切入到指定位置并运行的编程方式。 AOP详解可参考:https://blog.csdn.net/javazejian/article/det…

    Linux 2023年6月8日
    0109
  • Kubenertes-实战入门

    实战入门 Namespace Namespace是kubernetes系统中的一种非常重要资源,它的主要作用是用来实现 多套环境的资源隔离。 默认情况下,kubernetes集群中…

    Linux 2023年6月13日
    094
  • redis 基于SpringBoot Reids 的工具类

    redis 基于SpringBoot Reids 的工具类 package com.mhy.springredis.utils; import org.springframewor…

    Linux 2023年6月7日
    0122
  • 卡尔曼滤波(Kalman filter)(不完全介绍)

    1. Kalman filter基本介绍 卡尔曼滤波(Kalman filter)是一种高效的自回归滤波器,它能在存在诸多不确定性情况的组合信息中估计动态系统的状态,是一种强大的、…

    Linux 2023年6月14日
    0112
  • 基本数据类型的长度

    32位机器和64位机器中int、char等数据类型所占字节长度对比。 在32位机器和64机器中int类型都占用4个字节。编译器可以根据自身硬件来选择合适的大小,但是需要满足约束:s…

    Linux 2023年6月13日
    094
  • Redis集群-哨兵模式

    Sentinel(哨岗、哨兵)是Redis的主从架构的高可用性解决方案:由一个或多个Sentinel实例(instance)组成的Sentinel系统(system)监视任意多个R…

    Linux 2023年6月7日
    091
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球