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

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

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

杨树鹏身高,电玩菠菜,铁通dns服务器地址

上节以对话形式,大概说了几种客户端授权模式的原理,这节重点介绍hybrid模式在mvc下的使用。且为实现identityserver4从数据库获取user进行验证,并对claim进行权限设置打下基础(第五节介绍)。

本节内容比较多,且涉及一、二节的内容,如有不懂,可先熟悉一、二节知识。


一、新建授权服务,命名为authserver

(1)新建web api项目,不用配置https,不进行身份验证。

设置成控制台方式运行,端口设为5000。

安装identityserver4

在config.cs类中,添加如下代码:

public class config
    {

        public static list<testuser> getusers()
        {
            return new list<testuser>
            {
                new testuser
                {
                    subjectid = "1",
                    username = "test",
                    password = "123",

                    claims = new list<claim>
                    {
                        new claim("role", "user")
                    }
                },
                new testuser
                {
                    subjectid = "2",
                    username = "admin",
                    password = "123",

                    claims = new list<claim>
                    {
                        new claim("role", "admin")
                    }
                }
            };
        }

        public static ienumerable<identityresource> getidentityresources()
        {
            return new list<identityresource>
            {
                new identityresources.openid(),
                new identityresources.profile(),
                //new identityresource("roles","role",new list<string>{ "role"})
            };
        }

        public static ienumerable<apiresource> getapiresources()
        {
            return new list<apiresource>
            {
                new apiresource("api1", "my api")
                //new apiresource("api1", "my api",new list<string>(){ "role"})
            };
        }

        // clients want to access resources (aka scopes)
        public static ienumerable<client> getclients()
        {
            return new list<client>
            {
                new client
                {
                    clientid = "authserver",
                    allowedgranttypes = granttypes.clientcredentials,
                    clientsecrets =
                    {
                        new secret("secret".sha256())
                    },
                    allowedscopes = { "api1" },
                    claims= new list<claim>(){new claim("role","authserver") },
                    clientclaimsprefix = ""
                },
                // openid connect implicit flow client (mvc)
                new client
                {
                   clientid = "mvc",
                   clientname = "mvc client",
                   allowedgranttypes = granttypes.hybrid,
                   clientsecrets =
                   {
                       new secret("secret".sha256())
                   },
                   // 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,
                    //"roles"
                  }
                }
            };
        }
}

这里identityresource映射于那些关于用户信息的scope, apiresource映射于api资源的scopes。

 

(2)打开startup.cs,在configureservices里面调用addidentityserver来把identity server注册到asp.net core的容器里面;随后我调用了adddevelopersigningcredentials方法,它会创建一个用于对token签名的临时密钥材料(但是在生产环境中应该使用可持久的密钥材料)

 public void configureservices(iservicecollection services)
        {
            services.addmvc();

            services.addidentityserver()
               .adddevelopersigningcredential()
               .addtestusers(config.getusers())
               .addinmemoryidentityresources(config.getidentityresources())
               .addinmemoryapiresources(config.getapiresources())
               .addinmemoryclients(config.getclients());
        }

(3)打开configure方法,把identityserver添加到asp.net core的管道里。

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

            app.useidentityserver();
            //mvc配置
            app.usestaticfiles();
            app.usemvcwithdefaultroute();
        }

(4)然后下载登录用的ui: https://github.com/identityserver/identityserver4.quickstart.ui

把图中三个文件复制到authserver项目目录下。

复制完后项目如下:


 

二、新建mvc客户端,命名为mvcclient

(1)设置端口为5002。

修改start.cs的configureservices方法为:

public void configureservices(iservicecollection services)
        {
            services.configure<cookiepolicyoptions>(options =>
            {
                // this lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.checkconsentneeded = context => true;
                options.minimumsamesitepolicy = samesitemode.none;
            });


            services.addmvc();

            jwtsecuritytokenhandler.defaultinboundclaimtypemap.clear();

            services.addauthentication(options =>
            {
                options.defaultscheme = "cookies";
                options.defaultchallengescheme = "oidc";
            })
            .addcookie("cookies", options => 
            {
                //无权限,显示的页面
                options.accessdeniedpath = "/authorization/accessdenied";
            })
            .addopenidconnect("oidc", options =>
            {
                options.signinscheme = "cookies";

                options.authority = "http://localhost:5000";
                options.requirehttpsmetadata = false;

                options.clientid = "mvc";
                options.responsetype = "code id_token";
                options.scope.clear();
                options.scope.add("openid");
                options.scope.add("profile");
                //options.scope.add("roles");

                options.savetokens = true;
                options.clientsecret = "secret";
                options.getclaimsfromuserinfoendpoint = true;

                //options.claimactions.mapuniquejsonkey("role", "role");


                //options.tokenvalidationparameters = new tokenvalidationparameters
                //{
                //    nameclaimtype = jwtclaimtypes.givenname,
                //    roleclaimtype = jwtclaimtypes.role
                //};
            });
       }

addauthentication方法来添加和配置身份认证中间件。这里使用cookie作为验证用户的首选方式,而defaultscheme = "cookies",这个"cookies"字符串是可以任意填写的,只要与后边的一致即可。但是如果同一个服务器上有很多应用的话,这个scheme的名字不能重复。

defaultchanllangescheme设为"oidc", 这个名字与后边配置openidconnect的名字要一样. 当用户需要登陆的时候, 将使用的是openid connect scheme。

addcookie其参数是之前配置的defaultscheme名称,这配置了cookie的处理者,并让应用程序为我们的defaultscheme启用了基于cookie的身份认证。一旦id token验证成功并且转化为claims身份标识后,这些信息就将会保存于被加密的cookie里。

addopenidconnect方法添加了对openid connect流程的支持,它让配置了用来执行openid connect 协议的处理者。这个处理者会负责创建身份认证请求,token请求和其它请求,并负责id token的验证工作。它的身份认证scheme就是之前配置的"oidc",它的意思就是如果该客户端的某部分要求身份认证的时候,openid connect将会作为默认方案被触发(因为之前设置的defaultchallengescheme是"oidc", 和这里的名字一样)。

signinscheme和上面的defaultscheme一致,它保证身份认证成功的结果将会被保存在方案名为"cookies"的cookie里。

authority就是identity provider的地址。

clientidsecret要与identityprovider里面的值一样。

请求的scope有openid和profile,其实中间件默认也包括了这些scope,但是写出来更明确一些。

savetokens=true,表示允许存储从identity provider那里获得的tokens。

 

(2)修改configure方法为:

 public void configure(iapplicationbuilder app, ihostingenvironment env)
        {
            if (env.isdevelopment())
            {
                app.usedeveloperexceptionpage();
            }
            else
            {
                app.useexceptionhandler("/home/error");
            }

            app.useauthentication();

            app.usestaticfiles();
            app.usemvcwithdefaultroute();
        }

(3)然后对homecontroller加上身份验证。[authorize]

(4)再修改about的页面,显示user的claim信息。

@{
    viewdata["title"] = "about";
}
<h2>@viewdata["title"]</h2>

@*<dt>access token</dt>
<dd>@viewdata["accesstoken"]</dd>*@

<dl>
    @foreach (var claim in user.claims)
    {
        <dt>@claim.type</dt>
        <dd>@claim.value</dd>
    }
</dl>

 

(5)现在,可以运行authserver和mvcclient项目了。

(6)输入config文件中的testuser的用户,密码都设为123,点击login

允许授权

查看about页面,显示了user相关的claim信息。

(7)当然,登出功能还没实现,这里先实现登出。打开图中cshtml文件

添加如下代码:

 @if (user.identity.isauthenticated)
 {
     <li><a asp-area="" asp-controller="home" asp-action="logout">logout</a></li>
 }

然后在homecontroller控制器中添加logout方法

  public async task logout()

        {

            await httpcontext.signoutasync("cookies");

            await httpcontext.signoutasync("oidc");

        }

首先要清除本地的cookie,这个cookie的名字要与之前配置的默认方案里的名字一致,这一步就相当于登出mvc客户端。

后一行代码的作用是跳转回到identity provider,然后用户可以继续登出idp, 也就是idp会清除它的cookie。

(8)接着在authserver中的quickstart/account/accountoptions实现自动跳转回登录页面。

好了,登录登出实现完了,我们接着实现claim权限限制。


 

三、为mvc客户端设置claim身份验证

(1)添加testuser的claim中type为role

(2)定义用户信息scope的role信息

第一个参数是scope的名字,第二个参数是scope的显示名,第三个参数是它所包含的claim类型,这里就是“role”。

(3)然后还需要客户端允许请求“roles”这个scope

 

(4)mvc客户端的配置,打开mvc的startup,添加“roles”这个scope:options.scope.add("roles");

 把role claim 映射到user.claims里:options.claimactions.mapuniquejsonkey("role", "role");

 role claim映射成asp.net core mvc可以识别的角色roles。

options.tokenvalidationparameters = new tokenvalidationparameters
{
    nameclaimtype = jwtclaimtypes.givenname,
    roleclaimtype = jwtclaimtypes.role
};

这样mvc中的role就可以识别user.claims的role了。

(6)最后在mvcclient项目homecontroller中   about前,加上role为admin身份验证。[authorize(roles ="admin")]

然后运行,先用test账号登录进行验证。

发现点about页面没有权限进不去

然后登出,换admin账号登录

user.claims的role成功被mvc中角色role识别,展示about页面。


 

这节主要介绍hybrid在mvc下的使用,包括user的登录登出和claim对mvc的身份授权。

然而,这只是针对内存用户testuser进行操作的,显示实际项目中不能满足我们需求。下节将在本节的基础上介绍如何实现identityserver4从数据库获取user进行验证并对claim进行身份验证。

参考博客: 

源码地址:https://github.com/bingjian-zhu/mvc-hybridflowv0.git

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网