• IdentityServer4【QuickStart】之利用OpenID Connect添加用户认证


    利用OpenID Connect添加用户认证

    利用OpenID Connect添加用户认证

    在这个示例中我们想要通过OpenID Connect协议将交互用户添加到我们的IdentityServer上面。

    准备就绪后,我们会创建一个MVC的应用来使用IdentityServer做认证。

    添加UI

    关于该协议支持所需要的一切都内建到了IdentityServer中,你需要为登陆、登出、确认和错误等提供必要的UI页面。

    虽然在每一个实现了IdentityServer的服务中它所实现的外观和工作流程等都是不一样的,我们提供了一个MVC模板,你可以将其作为起点。

    可以从 Quickstart UI repo找到这个示例。你可以(使用github)克隆或者下载到你的桌面然后将控制器、视图、模型和Css样式表等放到你的应用里面。

    你也可以在你的项目的根目录下面运行下面这个命令行(在powershell)进行自动的安装:

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

    一点你安装好了这些之后,你也需要在Startup类中配置好你的MVC,这需要在ConfigureService里面将MVC添加到DI中并在Configure方法中将MVC中间件添加到管道上。

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
     
        // configure identity server with in-memory stores, keys, clients and scopes
        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients())
            .AddTestUsers(Config.GetUsers());
    }

    并且应该将MVC作为管道的最后一个中间件:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
     
        app.UseIdentityServer();
     
        app.UseStaticFiles();
        app.UseMvcWithDefaultRoute();
    }

    readme可以看到更多的信息。

    花费一些时间检查以下控制器和模型,你越了解他们,在后续的升级和改造过程中也会越容易。大多数代码都保存在一个QuickStart的文件夹中。如果这种方式不适合你的话,你可以自己修改成你要的风格。

    创建一个MVC客户端

    下一步你得创建一个MVC的应用。使用Asp.net core自带的模板就可以。不要配置认证信息。关于认证的信息需要你在应用里面自己配置。一旦你创建好应用后,将应用的端口号配置到5002上面。

    为了添加对OpenID Connect认证的支持,需要在Startup类中的ConfigureService方法中进行如下的配置。

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
     
        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
     
        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 = "mvc";
                options.SaveTokens = true;
            });
    }

    AddAuthentication 方法将认证服务添加到了DI系统中,我们使用了一个cookie作为认证用户的主要手段(通过options.DefaultScheme=“Cookies”来指定)。我们将DefaultChallengeScheme设置成“oidc”使用为当我们需要用户登陆的时候,我们要使用OpenID Connect的scheme。

    然后我们使用AddCookie方法添加一个对应的处理Cookie的handler(对应于options.DefaultScheme=“”Cookies“这个配置)。

    最后,AddOpenIdConnect方法配置了相应的handler(对应于options.DefaultChallengeScheme=”oidc”)来执行OpenID Connect协议。Authority指定了我们要新人的IdentityServer;然后通过ClientId标志了客户端;SiginScheme=“Cookies“这个表示当OpenId Connect协议执行完成之后会使用cookie handler来发布cookie。

    此外,我们关闭了JWT claim的类型映射以允许OpenId Connect中的claim类型。

    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
    然后为了认证服务会在每个请求中都执行,需要在Startup类中的Configure方法中配置认证的中间件:
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
     
        app.UseAuthentication();
     
        app.UseStaticFiles();
        app.UseMvcWithDefaultRoute();
    }

    认证中间件应该放在MVC的前面。

    最后一步是要触发认证。我们需要在home控制器上面添加[Autorize]特性。同时修改一下about页面:

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

    如果你现在使用浏览器访问了刚才配置好的控制器的路径,那么会有一个重定向发送到IdentityServer。这回导致一个错误因为MVC客户端还没有注册到Identityserver。

    添加对OpenID Connect Identity Scopes的支持

    和OAuth2.0相似的是,OpenID Connect同样使用了scopes这个概念。再一次声明:scopes代表了你想要保护的,同时,也是客户端想要访问的那种东西。与OAuth对比一下,scopes在OIDC中并不代表APIs,而是代表了用户的数据,比如user id、name或者email等。

    在这里阐述一下:scopes在OIDC里面是和claim挂钩的,他们之间的关系是1对多。打个比方,profile里面包含了许多的claim,包括first_name last_name等等。。

    在Config类中添加一个帮助方法,这个方法创建了一个IdentityResource的集合,它添加了对标准openid(subject id)和profile(用户的名、姓等等)scopes的支持。

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

    所有标准scopes对应的claims都能在specification找到。

    然后你得将上面配置好的添加到ConfgureService方法中,使用AddInmemoryIdentityResource:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
     
        // configure identity server with in-memory stores, keys, clients and scopes
        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients())
            .AddTestUsers(Config.GetUsers());
    }

    添加一个客户端用于演示OpenID Connect的隐式流程

    最后一步是在IdentityServer中为MVC客户端添加一个新的入口。

    在IdentitySErver中配置基于OpenId Connect的客户端和配置OAuth2.0的客户端有些相似。但是因为在OpenID Connect中经常会有交互发生,所有我们需要在配置中添加一写重定向。

    在客户端配置的代码中写入如下:

    public static IEnumerable<Client> GetClients()
    {
        return new List<Client>
        {
            // other clients omitted...
     
            // OpenID Connect implicit flow client (MVC)
            new Client
            {
                ClientId = "mvc",
                ClientName = "MVC Client",
                AllowedGrantTypes = GrantTypes.Implicit,
     
                // where to redirect to after login
                RedirectUris = { "http://localhost:5002/signin-oidc" },
     
                // where to redirect to after logout
                PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
     
                AllowedScopes = new List<string>
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile
                }
            }
        };
    }

    测试客户端

    现在终于都办妥了。

    导航到被保护的控制器上以便触发认证,这时你会发现被重定向到了IdentitySErver上的登陆页面:

     

    登陆成功后,会给用户呈现一个确认页面。在这里用户可以决定他是否要将一些访问资源的权限交给客户端。

    确认页面可以在配置中的RequireConsent属性上取消。

     

    最终页面会跳转到客户端应用上,展示用户的claim。

    添加登出

    在添加一个登出的功能吧。

    使用像identity server这样的身份验证服务,只需要清除本地应用程序cookie就不够了。此外,你还需要对身份服务器进行一次往返,以清除中心单点登录会话。

    确切的协议步骤是在OpenID Connect中间件中实现的,只需将以下代码添加到某个控制器中以触发信号:

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

    这将会清除本地的cookie然后重定向到Identityserver。Identtiyserver会清除它的Cookie然后给用户一个返回MVC应用的链接。

    进一步的尝试

    就像上面提到的,OpenId Connect中间件默认会请求profile scope。这个scope中包含了诸如name website等claim。

    将这些claim添加到TestUser上面,这样一来IdentityServer可以将他们放到Id token里面:

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

    下一次你再认证的时候,你的展示claims的页面就会展示这些额外的claim了。

    试着任意添加一些claim,或者更多的scopes。在OpenId Connect中间件中的Scope属性上面进行的配置会决定你发送到IdentityServer的认证请求中会包含那些scopes:

    services.AddAuthentication(option =>
    
                {
    
                    option.DefaultScheme = "cookies";
    
                    option.DefaultChallengeScheme = "oidc";
    
                }).AddCookie("cookies").AddOpenIdConnect("oidc", option =>
    
                {
    
                    option.Scope.Add("somescope");//这句
    
                });

    同样值得注意的是,检索令牌的claim是一个可扩展点----IProfileService。因为我们使用AddTestUsers,TestUserProfileService是默认被使用的。你可以检查源代码here 来看看它是如何工作的。

  • 相关阅读:
    Memcached初识
    排序
    查找
    Redis初识

    C#
    C#
    C#
    C#
    C#
  • 原文地址:https://www.cnblogs.com/pangjianxin/p/9370257.html
Copyright © 2020-2023  润新知