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 条评论
登录 后参与评论

相关文章

来自专栏SDNLAB

ONOS编程系列(二)命令行命令与服务开发

此文章承接ONOS编程系列(一) Application Tutorial ,如果尚未看过上一篇,请先看完上一篇,再回过头来看此篇。 本文章的目的在于让读者明白...

2999
来自专栏云知识学习

kubectl配置单、多集群访问

您可以通过 Kubernetes 命令行工具 kubectl 从本地客户端机器连接到 TKE 集群。

1642
来自专栏james大数据架构

入坑系列之HAProxy负载均衡

在大型系统设计中用代理在负载均衡是最常见的一种方式,而相对靠谱的解决方案中Nginx、HAProxy、LVS、F5在各大场中用得比较普遍,各有各的优势和使用场...

47810
来自专栏桥路_大数据

使用Git+Shell自动化部署发布springboot WEB应用

2865
来自专栏匠心独运的博客

消息中间件—RabbitMQ(集群原理与搭建篇)

摘要:实际生产应用中都会采用消息队列的集群方案,如果选择RabbitMQ那么有必要了解下它的集群方案原理 一般来说,如果只是为了学习RabbitMQ或者验证业...

1412
来自专栏hbbliyong

SQLite3创建数据库的方法

    上次刚接触SqlLite,不知道怎么创建数据库,现在做下总结:   界面和MYSQL一样,都是CMD界面,但不是在SQLite.exe中创建数据库: 首...

3354
来自专栏Albert陈凯

linux目录结构和常用命令

一、Linux目录结构 你想知道为什么某些程序位于/bin下,或者/sbin,或者/usr/bin,或/usr/sbin目录下吗?例如,less命令位于/us...

2424
来自专栏晓晨的专栏

IdentityServer Topics(1)- 启动说明

1463
来自专栏linux系统运维

VM虚拟机的下载以及安装centos7

1383
来自专栏Java Edge

ZooKeeper分布式入门实战(三)-基本特性1 zookeeper常用命令行操作2 session的基本原理与create命令的使用3 set与delete命令的使用4 zk特性 – 理解watc

912

扫码关注云+社区