当前位置: 移动技术网 > IT编程>开发语言>.net > 从Client应用场景介绍IdentityServer4(二)

从Client应用场景介绍IdentityServer4(二)

2018年12月19日  | 移动技术网IT编程  | 我要评论

本节介绍client的clientcredentials客户端模式,先看下画的草图:

一、在server上添加动态新增client的api 接口。

为了方便测试,在server服务端中先添加swagger,添加流程可参考:

 

在valuescontroller控制器中注入configurationdbcontext上下文,此上下文可用来加载或配置identityserver4.entityframework的client、身份信息、api资源信息或cors数据等。

在valuescontroller中实添加以下代码:

        private configurationdbcontext _context;
        public valuescontroller(configurationdbcontext context)
        {
            _context = context;
        }

添加动态新增client的api接口:

        [httppost]
        public iactionresult post([frombody] identityserver4.entityframework.entities.client client)
        {
            var res = _context.clients.add(client);
            if(_context.savechanges() >0)
                return ok(true);
            else
                return ok(false);
        }

控制器代码如下:


 

二、对server上的api进行保护

(1)安装identityserver4.accesstokenvalidation包

(2)在startup.cs中configureservices方法添加如下代码:

            //protect api
            services.addmvccore()
            .addauthorization()
            .addjsonformatters();

            services.addauthentication("bearer")
                .addidentityserverauthentication(options =>
                {
                    options.authority = "http://localhost:5000";
                    options.requirehttpsmetadata = false;

                    options.apiname = "api1";
                });

addauthentication把bearer配置成默认模式,将身份认证服务添加到di中。

addidentityserverauthentication把identityserver的access token添加到di中,供身份认证服务使用。

(3)在startup.cs中configure方法添加如下代码:

      public void configure(iapplicationbuilder app, ihostingenvironment env)
        {
            //if (env.isdevelopment())
            //{
            //    app.usedeveloperexceptionpage();
            //}

            //addswagger
            app.useswagger();
            app.useswaggerui(c =>
            {
                c.swaggerendpoint("/swagger/v1/swagger.json", "server接口文档");
            });

            initializedatabase(app);
            app.useauthentication();
            app.useidentityserver();
            app.usemvc();
        }

useauthentication将身份验证中间件添加到管道中,以便在每次调用主机时自动执行身份验证。

(4)在valuescontroller控制器中添加[authorize]

 

(5)在项目属性->调试 中,启动浏览器,并设成swagger,如图:

(6)启动项目,并调用第一个get接口。

显示unauthorized(未授权),证明[authorize]起作用了。


 

三、搭建client客户端

(1)新建一个控制台程序,安装identitymodel包

(2)添加类idshelper.cs,添加客户端请求api接口代码。

public class idshelper
    {
        public static async task mainasync()
        {
            try
            {
                discoveryresponse disco = await discoveryclient.getasync("http://localhost:5000");
                if (disco.iserror)
                {
                    console.writeline(disco.error);
                    return;
                }

                tokenclient tokenclient = new tokenclient(disco.tokenendpoint, "client", "secret");
                var tokenresponse = await tokenclient.requestclientcredentialsasync("api1");

                if (tokenresponse.iserror)
                {
                    console.writeline(tokenresponse.error);
                    return;
                }
                console.writeline(tokenresponse.json);
                var client = new httpclient();
                client.setbearertoken(tokenresponse.accesstoken);
                var response = await client.getasync("http://localhost:5000/api/values/");
                if (!response.issuccessstatuscode)
                {
                    console.writeline(response.statuscode);
                }
                else
                {
                    var content = await response.content.readasstringasync();
                    console.writeline(content);
                }
            }
            catch (exception ex)
            {

            }
        }
}

(3)修改program.cs代码,如下:

class program
    {
        static void main(string[] args)
       => idshelper.mainasync().getawaiter().getresult();
    }

(4)按ctrl+f5,可以获取到access token和接口返回值

复制token,用postman调用,成功获取到了接口返回值。


 

四、测试动态新增client接口

安装identityserver4包。

安装identityserver4.entityframework包。

在idshelper.cs类中添加post方法:

public static async task post()
        {
            try
            {
                discoveryresponse disco = await discoveryclient.getasync("http://localhost:5000");
                if (disco.iserror)
                {
                    console.writeline(disco.error);
                    return;
                }

                tokenclient tokenclient = new tokenclient(disco.tokenendpoint, "client", "secret");
                var tokenresponse = await tokenclient.requestclientcredentialsasync("api1");

                if (tokenresponse.iserror)
                {
                    console.writeline(tokenresponse.error);
                    return;
                }
                console.writeline(tokenresponse.json);
                var client = new httpclient();
                client.setbearertoken(tokenresponse.accesstoken);

                client c1 = new client
                {
                    clientid = "test",
                    allowedgranttypes = granttypes.clientcredentials,
                    clientsecrets =
                    {
                        new secret("secret".sha256())
                    },
                    allowedscopes = { "api1" }
                };
                string strjson = jsonconvert.serializeobject(c1 .toentity());
                httpcontent content = new stringcontent(strjson);
                content.headers.contenttype = new system.net.http.headers.mediatypeheadervalue("application/json");
                //由httpclient发出post请求
                task<httpresponsemessage> response = client.postasync("http://localhost:5000/api/values/", content);

                if (response.result.statuscode != system.net.httpstatuscode.ok)
                {
                    console.writeline(response.result.statuscode);
                }
                else
                {
                    console.writeline(response.result.content.readasstringasync().result);
                }
            }
            catch (exception ex)
            {

            }
        }

顺便把main中改成对post调用:

static void main(string[] args)

       => idshelper.post().getawaiter().getresult();

按ctrl+f5,调用新增client的接口,并成功返回true。

同时可以在数据库中的client表找到相关记录。需要注意的是,不能添加相同client id的client。


 

五、在client中添加claim信息,并在api接口中对claim信息进行验证。

关于claim的介绍可以看这篇文章:

这里把claim简单当做用户的身份信息使用,修改post方法里面的client:

                client c1 = new client
                {
                    clientid = "superadmin",
                    allowedgranttypes = granttypes.clientcredentials,
                    clientsecrets =
                    {
                        new secret("secret".sha256())
                    },
                    allowedscopes = { "api1" },
                    claims = new list<claim>
                    {
                        new claim(jwtclaimtypes.role, "admin")
                    }
                };

可以看出,claims为list,可以是很多个角色,这里只添加一个。

ctrl+f5,运行成功添加superadmin client。

 

现在,需要对server服务端的新增client接口进行claim身份验证,添加如下代码:

   [authorize(roles ="admin")]

然后再客户端修改授权的账号为superadmin。

tokenclient tokenclient = new tokenclient(disco.tokenendpoint, "superadmin", "secret");

ctrl+f5运行

问题出现了,返回了forbidden,没有权限进行访问。

这时候我们上官网查阅了资料,发现在添加client的claim时候,identityserver entityframework会为claim的role添加一个默认前缀,为client_。所以,实际上它为client_role

而服务端只能对role进行验证。

此时我们需要把claim的默认前缀去掉,设置为空clientclaimsprefix = ""

 

去掉server的role验证,添加形如下面代码的client。

client c1 = new client
                {
                    clientid = "adminclient",
                    allowedgranttypes = granttypes.clientcredentials,
                    clientsecrets =
                    {
                        new secret("secret".sha256())
                    },
                    allowedscopes = { "api1" },
                    claims = new list<claim>
                    {
                        new claim(jwtclaimtypes.role, "admin")
                    },
                    clientclaimsprefix = "" //把client_ 前缀去掉
                };

 ctrl+f5,运行成功添加adminclient client,这次的是role为admin。

然后重新再server服务端加上[authorize(roles ="admin")]

同时修改验证账号为adminclient。

tokenclient tokenclient = new tokenclient(disco.tokenendpoint, "adminclient", "secret");

最后运行程序,成功地在[authorize(roles ="admin")]权限下访问并新增了client。


 

六、需要注意的问题

(1)新增client到数据库时候,这里需要接收identityserver4.entityframework.entities.client

而不是identityserver4.models.client,否则api接口在接收和转化client模型的时候会报错。

(2)此外,本节介绍的client的allowedgranttypes 都为 granttypes.clientcredentials,相应的,客户端请求是,需要用requestclientcredentialsasync方法。

最后再次提下,clientcredentials模式的适用场景:用于和用户无关,服务与服务之间直接交互访问资源


 

server服务端源码地址:https://github.com/bingjian-zhu/server

client客户端源码地址:https://github.com/bingjian-zhu/client

文中如有错漏,欢迎指正。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网