回顾下clientcredentials模式,在resourceapi中定义了我们公开服务,第三方网站想要去访问resourceapi则需要在身份验证服务中获取toekn,根据token的内容,硬编码去访问公开服务(resapi),这个还是非常简单的,但!仔细思考下,我们在客户端当中设置了对应的身份验证服务中心的地址,那么也就是可以有多对多的情况,当然我们的第三方网站无需多言去关注这些。

public void configureservices(iservicecollection services)
        {
            services.addauthentication("bearer")
                .addidentityserverauthentication(options =>
                {
                    options.authority = "https://localhost:5000";
                    options.requirehttpsmetadata = false;
                    options.apiname = "api";
                });
            services.addmvc().setcompatibilityversion(compatibilityversion.version_2_1);
        }

  下面咱说下密码模式,这个模式安全级别比clientcredentials高得多,第一步我们需要修改一下我们的config文件.然后第二步就是添加我们的testuser对象.

public static ienumerable<client> getclients()
        {
            return new list<client>
            {
                new client()
                {
                    clientid = "client",
                    allowedgranttypes = granttypes.clientcredentials,//客户端登陆模式
                    clientsecrets ={
                        new secret("secret".sha256())
                    },
                    allowedscopes = {"api"}
                },
                new client()
                {
                    clientid = "pwdclient",
                    allowedgranttypes = granttypes.resourceownerpassword,//密码授权登陆模式
                    clientsecrets ={
                        new secret("secret".sha256())
                    },
                    allowedscopes = {"api"}
                }
            };
        }

第二部testuser对象由identityserver4.test 给我们提供了,我们引入就ok,然后添加该方法用于测试.

public static list<testuser> gettestusers()
        {
            return new list<testuser>
            {
                new testuser()
                {
                    subjectid = "1",
                    username = "zara",
                    password = "112233"
                }
            };
        }

当然,你还需要将测试数据注入到core中,我们需要修改下原来的stratup.cs类.

services.addidentityserver()//将idserer di到.netcore
                .adddevelopersigningcredential()
                .addinmemoryapiresources(config.getresource())//添加公开服务
                .addinmemoryclients(config.getclients())//客户端模拟数据
                .addtestusers(config.gettestusers());//用户测试数据

 下面我们用postman来测试一下,先用原来的客户端模式,看,我们对客户端模式不会影响。 

现在我们再试一下密码登陆模式,首先获取token!

我们再去resourceapi中进行测试,ok,没问题!

现在我们创建一个客户端,用于硬编码的密码登陆。

 

using identitymodel.client;
using system;
using system.net.http;

namespace thirdpartysolucation
{
    public static class passwordlogin
    {
        public static void login()
        {
            var diso = discoveryclient.getasync("https://localhost:5000").result;
            if (diso.iserror)
            {
                console.writeline(diso.error);
            }
            var tokenclient = new tokenclient(diso.tokenendpoint, "pwdclient", "secret");
            var tokenresponse = tokenclient.requestresourceownerpasswordasync("zara","112233").result;
            if (tokenresponse.iserror)
            {
                console.writeline(tokenresponse.error);
            }
            else
            {
                console.writeline(tokenresponse.json);
            }

            httpclient httpclient = new httpclient();
            httpclient.setbearertoken(tokenresponse.accesstoken);
            var response = httpclient.getasync("http://localhost:5001/api/values").result;
            if (response.issuccessstatuscode)
            {
                console.writeline(response.content.readasstringasync().result);
            }
            console.writeline();
        }
    }
}

启动,结果如下:

 

如果需要不做secret验证,在config中添加该参数:

new client()
                {
                    clientid = "pwdclient",
                    allowedgranttypes = granttypes.resourceownerpassword,
                    clientsecrets ={
                        new secret("secret".sha256())
                    },
                    requireclientsecret = false,
                    allowedscopes = {"api"}
                }

上图是基本的客户端登陆模式,而密码模式呢,则会在获取获取token中body上下文中加入username,password来加以复杂认证,但是用密码也不太可靠,抽时间我们说下授权码模式,说一说它们的区别与实现。