ASP.NET Core的身份认证框架IdentityServer4(9)-使用OpenID Connect添加用户认证

OpenID Connect

OpenID Connect 1.0是OAuth 2.0协议之上的一个简单的身份层。 它允许客户端基于授权服务器执行的身份验证来验证最终用户的身份,以及以可互操作和类似REST的方式获取关于最终用户的基本配置文件信息。

OpenID Connect允许所有类型的客户端(包括基于Web的移动和JavaScript客户端)请求和接收关于认证会话和最终用户的信息。 规范套件是可扩展的,允许参与者使用可选功能,例如身份数据的加密,OpenID提供商的发现和会话管理。

OpenID Connect 和 OAuth的关系

OpenID Connect 在OAuth2上构建了一个身份层,是一个基于OAuth2协议的身份认证标准协议。我们都知道OAuth2是一个授权协议,它无法提供完善的身份认证功能,OpenID Connect 使用OAuth2的授权服务器来为第三方客户端提供用户的身份认证,并把对应的身份认证信息传递给客户端,且可以适用于各种类型的客户端(比如服务端应用,移动APP,JS应用),且完全兼容OAuth2,也就是说你搭建了一个OpenID Connect 的服务后,也可以当作一个OAuth2的服务来用。应用场景如图 (摘自:http://www.cnblogs.com/linianhui/archive/2017/05/30/openid-connect-core.html

简而言之,OpenID Connect是在OAuth2.0上进行的一个扩展协议,OpenID Connect=Identity +OAuth 2.0,OpenID Connect主要用于身份认证(Authentication),OAuth主要用于授权(Authorization)。

更深入了解OpenID Connect和OAuth,如果你准备使用IdentityServer4,十分推荐阅读这几篇文章:http://www.cnblogs.com/linianhui/category/929878.html

创建一个MVC客户端

1.新建一个ASP.NET Core MVC应用程序

2.配置 OpenID Connect 认证

在类StartupConfigureServices方法中添加以下代码:

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将认证服务添加到依赖注入容器中,使用Cookie作为验证用户的主要方法(通过"Cookies"作为 DefaultScheme)。

DefaultChallengeScheme 设置为"oidc"(OIDC是OpenID Connect的简称),因为当我们需要用户登录时,我们将使用OpenID Connect方案。

然后我们使用AddCookie添加可以处理Cookie的处理程序。

最后,AddOpenIdConnect用于配置执行OpenID Connect协议的处理程序。Authority表示id4服务的地址。 然后我们通过ClientId识别该客户端。SignInScheme 用于在OpenID Connect协议完成后使用cookie处理程序发出cookie。 而SaveTokens用于在Cookie中保存IdentityServer中的令牌(稍后将需要)。

然后确保在每个请求上执行认证服务,在Startup中的Configure方法添加UseAuthentication

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

    app.UseAuthentication();

    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();
}

验证中间件应该在MVC之前添加。

最后一步是触发认证。为了进入HomeController,并在其中一个Action上添加特性[Authorize]

还要修改该Action的View以显示用户的信息,例如:

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

如果您现在使用浏览器访问HomeController,将会导致重定向到IdentityServer,这将导致错误,因为MVC客户端尚未注册。

添加OpenID Connect Identity Scopes的支持

与OAuth 2.0类似,OpenID Connect也使用Scopes概念。 再次,Scopes代表您想要保护的客户端希望访问的内容。 与OAuth相反,OIDC中的范围不代表API,而是代表用户ID,姓名或电子邮件地址等身份信息。

Config.cs中添加如下代码:

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

所有标准Scopes及其相应的声明都可以在OpenID Connect规范中找到。

然后,您需要将这些身份资源添加到Startup.cs中的IdentityServer配置中。使用AddInMemoryIdentityResources扩展方法调用AddIdentityServer()

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 implicit flow 添加客户端

Implicit Flow指的是使用OAuth2的Implicit流程获取Id Token和Access Token

最后一步是将MVC客户端的配置添加到IdentityServer。

基于OpenID Connect的客户端与我们迄今添加的OAuth 2.0客户端非常相似。 但是由于OIDC中的流程始终是交互式的,我们需要在配置中添加一些重定向URL。

将以下内容添加到您的客户端配置:

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
            }
        }
    };
}

测试客户端

通过访问受保护的Action来触发身份验证握手。 你应该看到重定向到IdentityServer的登录页面。

成功登录后,用户将看到同意画面。 在这里,用户可以决定是否要将他的身份信息发布到客户端应用程序。

可以使用客户端对象上的RequireConsent属性以每个客户端为基础关闭同意询问。

最后浏览器重定向到客户端应用程序,该应用程序显示了用户的声明。

在开发过程中,您有时可能会看到一个异常,说明令牌无法验证。 这是因为签名密钥信息是即时创建的,并且只保存在内存中。 当客户端和IdentityServer不同步时,会发生此异常。 只需在客户端重复操作,下次元数据已经追上,一切都应该正常工作。

添加注销

最后一步是给MVC客户端添加注销功能。

使用IdentityServer等身份验证服务,仅清除本地应用程序Cookie是不够的。 此外,您还需要往身份服务器交互,以清除单点登录会话。

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

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

这将清除本地cookie,然后重定向到IdentityServer。 IdentityServer将清除它的cookie,然后给用户一个链接返回到MVC应用程序。

进一步实验

如上所述,OpenID Connect中间件默认要求配置 profile scope。 这个scope还包括像名字或网站这样的声明。

让我们将这些声明添加到用户,以便IdentityServer可以将它们放入身份令牌中:

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")
            }
        }
    };
}

下一次您进行身份验证时,你的声明页面现在将显示额外的声明。

OpenID Connect中间件上的Scope属性是您配置哪些Scope将在身份验证期间发送到IdentityServer。

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

地址

Demo下载地址:https://github.com/IdentityServer/IdentityServer4.Samples/tree/release/Quickstarts/3_ImplicitFlowAuthentication

参考官方文档:https://identityserver4.readthedocs.io/en/release/quickstarts/3_interactive_login.html

官方的Demo已经更新到最新的.NET Core 2.0 所以我不在单独写Demo 了,直接用的官方的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏DannyHoo的专栏

错误——持续更新

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

901
来自专栏hotqin888的专栏

froala富文本编辑器与golang、beego,脱离ueditor苦海

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

1172

使用Python和Requests访问HP OpenStack Nova

因此,我申请加入新的惠普云服务的免费和私人测试版,已经被惠普云团队所接受,今天我终于有一段时间在惠普云端使用OpenStack API。我将从我对服务的第一印象...

1875
来自专栏FreeBuf

Android安全几道入门题目

Android系统由于其开源的属性,市场上针对开源代码定制的ROM参差不齐,在系统层面的安全防范和易损性都不一样,android应用市场对app的审核相对 iO...

3725
来自专栏ppjun专栏

Xposed去抖音提示

特别感谢https://www.52pojie.cn/thread-684757-1-1.html 官方教程:https://github.com/rovo8...

922
来自专栏君赏技术博客

百思不得姐数据挖掘第三篇

播放视频的界面现在只剩下视频的功能了,对于这种播放视频的应该属于功能块。我们可以单独把这个功能提取出来。

742
来自专栏晓晨的专栏

IdentityServer4(10)- 添加对外部认证的支持之QQ登录

1593
来自专栏施炯的IoT开发专栏

Windows Mobile 6.5 开发者工具包

    在一段时间的等待之后,Microsoft终于在其下载中心开放了《Windows Mobile 6.5 开发者工具包》的下载。这对于广大Windows M...

1866
来自专栏深度学习那些事儿

macOS使用django安装mysqlclient遇到的问题(mysqlclient 1.3.3 or newer is required)

最近需要使用django搭建一个网站,使用的数据库是mysql。 mac电脑里面已经安装好了mysql-5.7-community。 之前使用的python...

1614
来自专栏walterlv - 吕毅的博客

Automatically increase the semantic version using GitVersion

发布于 2018-04-18 12:51 更新于 2018-09...

362

扫码关注云+社区