ASP.NET Core的身份认证框架IdentityServer4(8)- 使用密码认证方式控制API访问

前言

本文及IdentityServer这个系列使用的都是基于.net core 2.0的。上一篇博文在API项目中我使用了Microsoft.AspNetCore.Authentication.JwtBearer组件来代替IdentityServer4.AccessTokenValidation组件,今天(2017-9-12)我发现后者已经更新到了2.0.0,支持.net core 2.0,所以现在所使用的组件已经更新为后者,在代码里我有详细注释。

资源所有者密码授权

OAuth 2.0 资源所有者密码授权允许一个客户端发送用户名和密码到IdentityServer并获得一个表示该用户的可以用于访问api的Token。

该规范建议仅对“受信任”应用程序使用资源所有者密码授权。 一般来说,当您要验证用户并请求访问令牌时,通常使用交互式OpenID Connect流会更好。

不过,这个授权类型允许我们在 IdentityServer 快速入门中引入 用户 的概念,这是我们要展示它的原因。

添加用户

就像基于内存存储的资源(即 范围 Scopes)和客户端一样,对于用户也可以这样做。

注意:查看基于 ASP.NET Identity 的快速入门以获得更多关于如何正确存储和管理用户账户的信息。

TestUser类型表示一个测试用户及其身份信息。让我们向配置类(如果你有严格按照顺序进行演练,那么配置类应该在 QuickstartIdentityServer 项目的 Config.cs 文件中)中添加以下代码以创建一对用户:

首先添加以下语句 到Config.cs文件中:

public static List<TestUser> GetUsers()
{
    return new List<TestUser>
    {
        new TestUser
        {
            SubjectId = "1",
            Username = "alice",
            Password = "password"
        },
        new TestUser
        {
            SubjectId = "2",
            Username = "bob",
            Password = "password"
        }
    };
}

然后将测试用户注册到 IdentityServer:

public void ConfigureServices(IServiceCollection services)
{
    // 使用内存存储,密钥,客户端和资源来配置身份服务器。
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryApiResources(Config.GetApiResources())//添加api资源
        .AddInMemoryClients(Config.GetClients())//添加客户端
        .AddTestUsers(Config.GetUsers()); //添加测试用户
}

AddTestUsers 方法帮我们做了以下几件事:

  • 为资源所有者密码授权添加支持
  • 添加对用户相关服务的支持,这服务通常为登录 UI 所使用(我们将在下一个快速入门中用到登录 UI)
  • 为基于测试用户的身份信息服务添加支持(你将在下一个快速入门中学习更多与之相关的东西)

为资源所有者密码授权添加一个客户端定义

你可以通过修改 ·AllowedGrantTypes· 属性简单地添加对已有客户端授权类型的支持。

通常你会想要为资源所有者用例创建独立的客户端,添加以下代码到你配置中的客户端定义中:

// client want to access resources (aka scopes)
public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        new Client
        {
            ClientId = "client",
            // 没有交互性用户,使用 clientid/secret 实现认证。
            AllowedGrantTypes = GrantTypes.ClientCredentials,
            // 用于认证的密码
            ClientSecrets = 
            {
                new Secret("secret".Sha256())
            },
            // 客户端有权访问的范围(Scopes)
            AllowedScopes = { "api1" }
        },
        // resource owner password grant client
        new Client
        {
            ClientId = "ro.client",
            AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            AllowedScopes = { "api1" }
        }
    };
}

使用密码授权请求一个令牌 客户端看起来跟之前客户端证书授权的客户端是相似的。主要差别在于现在的客户端将会以某种方式收集用户密码,然后在令牌请求期间发送到令牌服务。

IdentityModel 的 TokenClient 在这里再次为我们提了供帮助:

// 从元数据中发现客户端
var disco = await DiscoveryClient.GetAsync("http://localhost:5000");

// 请求令牌
var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.client", "secret");
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("alice", "password", "api1");//使用用户名密码

if (tokenResponse.IsError)
{
    Console.WriteLine(tokenResponse.Error);
    return;
}

Console.WriteLine(tokenResponse.Json);
Console.WriteLine("\n\n");

当你发送令牌到身份 API 端点的时候,你会发现与客户端凭证授权 相比,资源所有者密码授权有一个很小但很重要的区别。访问令牌现在将包含一个 sub 信息,该信息是用户的唯一标识。sub 信息可以在调用 API 后通过检查内容变量来被查看,并且也将被控制台应用程序显示到屏幕上。

sub 信息的存在(或缺失)使得 API 能够区分代表客户端的调用和代表用户的调用。

下面这张图,是理解的客户端请求流程,

关于上图的补充说明,这里讲一下。api资源收到第一个请求之后,会去id4服务器公钥,然后用公钥验证token是否合法,如果合法进行后面后面的有效性验证。有且只有第一个请求才会去id4服务器请求公钥,后面的请求都会用第一次请求的公钥来验证,这也是jwt去中心化验证的思想。

最后github地址:https://github.com/stulzq/IdentityServer4.Samples/tree/master/Quickstarts/2_ResourceOwnerPasswords 如果你觉得对你有用,欢迎star

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏农夫安全

【笔记】记录Cy牛的任意密码重置姿势

跟第三个有点类似,只判断了接收端和验证码是否一致,未判断接收端是否和用户匹配,因此修改接收端可达到重置目的

1112
来自专栏逢魔安全实验室

渗透技巧 | Windows上传并执行恶意代码的N种姿势

? 简介 在各种钓鱼、挖矿、勒索、组建僵尸网络、基础渗透、后渗透过程当中,攻击者都会通过一些方法去下载执行恶意代码并执行完成攻击操作,比如前段时间通过Off...

4295
来自专栏FreeBuf

任意用户密码重置(一):重置凭证泄漏

在逻辑漏洞中,任意用户密码重置最为常见,可能出现在新用户注册页面,也可能是用户登录后重置密码的页面,或者用户忘记密码时的密码找回页面。其中,密码找回功能是重灾区...

1966
来自专栏张戈的专栏

WP Super Cache静态缓存插件纯代码版(兼容多域名网站)

中午,小熊发来一篇来自歧路亡羊博客的精彩教程:《wordpress 利用代码来实现缓存》。粗略看了一下,发现这个代码在几个月之前我就用过,不过由于此代码无法区分...

3977
来自专栏不想当开发的产品不是好测试

mac下的抓包工具 -- Charles

换了mac电脑,?,需要抓包,之前windows上使用的fiddler使用不了,需要找到替代工具,随意百度下知道了 -- Charles

602
来自专栏GreenLeaves

邮件发送功能开发

作为一名.Net开发,"邮件发送"功能的开发和使用是必须要掌握的,因为这个功能作为“消息推送”的一种手段经常出现在各种.Net系统中,所以本文将对.Net平台下...

2397
来自专栏Hadoop实操

Cloudera Navigator异常分析

在Cloudera Manager的管理界面查看Navigator服务正常,无任何告警

41710
来自专栏Java学习123

tomcat结合nginx使用小结

3137
来自专栏python爬虫日记

基于esky实现python应用的自动升级

Esky is an auto-update framework for frozen Python applications. It provides a s...

933
来自专栏吴文斌的专栏

whistle:全新的跨平台web调试工具

whistle是基于Node实现的跨平台web调试代理工具,类似的工具有Windows平台上的Fiddler+Willow,基于Java实现的Charles,及...

2.4K0

扫码关注云+社区