欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

使用.Net Core + Vue + IdentityServer4 + Ocelot 实现一个简单的DEMO +源码

程序员文章站 2022-07-21 19:07:50
.Net Core + Vue + IdentityServer4 + Ocelot ......

运行环境

vue 使用的是d2admin:
github地址:https://github.com/fengddd/permissionadmin.git
net core的环境:webapi 使用的是:net core sdk2.1 identityserver和ocelot:net core sdk2.2
github地址:https://github.com/fengddd/identityserverocelotdemo.git
我也是在初学阶段,所以有些地方可能描述的不是很清楚,可以下载源码查看,也可能大家一起交流,学习

建立identityserver4项目


根据 根据edison zhou大佬的博客,配置好 quickstart ui 以及identityserver的依赖项
新建identityserver4的配置文件identityconfig

   public static ienumerable<identityresource> getidentityresources()
    {
        return new identityresource[]
        {
            new identityresources.openid(),
            new identityresources.profile(),
            new identityresource("delimitclaim","delimitclaim",new list<string>(){ "role", "name"}),  //在claims添加role 和 name信息
        };
    }     
    public static ienumerable<apiresource> getapiresource()
    {
        return new list<apiresource>
        {              
            new apiresource("identityserverapi", "identityserverapi"),
        };
    }
   public static ienumerable<client> getclients()
    {
         new client
            {                
                clientid = "js", //客户端id
                clientname = "javascript client", //客户端名称
                allowedgranttypes = granttypes.code, //授权模式
                //allowedgranttypes = granttypes.implicit,
                requirepkce = true,
                requireclientsecret = false,
                requireconsent = false, //禁用 consent 页面确认                    
                allowaccesstokensviabrowser = true,
                alwaysincludeuserclaimsinidtoken = true,
                redirecturis =
                {
                    "http://localhost:8080/#/identityservercallback",  //登陆后回调页面 
                    "http://localhost:8080/#/identityserverrefreshtoken" //刷新token的页面
                },
                postlogoutredirecturis = { "http://localhost:8080/#/identityserverclient" },//注销退出后跳转的页面(登录页)                   
                allowedcorsorigins = { "http://localhost:8080" }, //跨域
                accesstokenlifetime = 60, //accesstoken 的有效时间
                allowedscopes =
                {
                    identityserverconstants.standardscopes.openid,
                    identityserverconstants.standardscopes.profile,
                    "identityserverapi", //授权的scopes
                    "delimitclaim" //claims 信息
                },
                allowofflineaccess = true,                  
            }
    }

有时我们需要自定义验证以及自定义一些claim的信息,所以需要实现 iprofileservice 接口

public virtual task getprofiledataasync(profiledatarequestcontext context)
    {
        context.logprofilerequest(logger);
        //判断是否有请求claim信息
        if (context.requestedclaimtypes.any())
        {
            var userclaims = new list<claim>
            {
                new claim("demo1", "测试1"),
                new claim("demo2", "测试2"),
            };
            list<testuser> userlist = new list<testuser>()
            {
                new testuser(){subjectid = "cfac01a9-ba15-4678-bccb-cc22d7896362",password = "123456",username="李锋",claims = userclaims},
                new testuser(){subjectid = "cfac01a9-ba15-4678-bccb-cc22d7855555",password = "123456",username="张三"},
            };
            testuserstore userstore = new testuserstore(userlist);
            //根据用户唯一标识查找用户信息
            var user = userstore.findbysubjectid(context.subject.getsubjectid());
            if (user != null)
            {
                //调用此方法以后内部会进行过滤,只将用户请求的claim加入到 context.issuedclaims 集合中 这样我们的请求方便能正常获取到所需claim
                context.addrequestedclaims(user.claims);
            }
            //context.issuedclaims=userclaims;
        }
        context.logissuedclaims(logger);
        return task.completedtask;
    }     
    /// <summary>
    /// 验证用户是否有效 例如:token创建或者验证
    /// </summary>
    /// <param name="context">the context.</param>
    /// <returns></returns>
    public virtual task isactiveasync(isactivecontext context)
    {
        logger.logdebug("isactive called from: {caller}", context.caller);
        var userclaims = new list<claim>
        {
            new claim("demo1", "测试1"),
            new claim("demo2", "测试2"),
        };
        list<testuser> userlist = new list<testuser>()
        {
            new testuser(){subjectid = "cfac01a9-ba15-4678-bccb-cc22d7896362",password = "123456",username="李锋",claims = userclaims},
            new testuser(){subjectid = "cfac01a9-ba15-4678-bccb-cc22d7855555",password = "123456",username="张三"},
        };
        testuserstore userstore = new testuserstore(userlist);
        var user = userstore.findbysubjectid(context.subject.getsubjectid());
        context.isactive = user?.isactive == true;
        return task.completedtask;
    }

其中关于claims的地方这里做测试所以直接实例出来的数据,这里可以通过读取数据库进行验证,以及添加claims的信息
在startup 的configureservices 注入identityserver信息 ,configure下注册useidentityserver中间件

  services.addidentityserver()
            .adddevelopersigningcredential()
            .addinmemoryidentityresources(identityconfig.getidentityresources())
            .addinmemoryapiresources(identityconfig.getapiresource())
            .addinmemoryclients(identityconfig.getclients())
            //.addtestusers(identityconfig.getusers().tolist())
            .addprofileservice<identityprofileservice>(); //使用的是code模式,使用自定义claims信息
            //.addresourceownervalidator<identityresourceownerpasswordvalidator>();

 app.useidentityserver();

然后找到quickstart中的登录方法,这里修改为从数据库读取验证用户信息
使用.Net Core + Vue + IdentityServer4 + Ocelot 实现一个简单的DEMO +源码

建立vue项目


安装依赖项:oidc-client :npm install oidc-client --save axios:npm install axios --save
添加 identityserverclient 页面
使用.Net Core + Vue + IdentityServer4 + Ocelot 实现一个简单的DEMO +源码
添加 identityservercallback页面
使用.Net Core + Vue + IdentityServer4 + Ocelot 实现一个简单的DEMO +源码
添加 identityservercallback页面
使用.Net Core + Vue + IdentityServer4 + Ocelot 实现一个简单的DEMO +源码
访问identityserverclient 页面时会自动跳转到identityserver4的登录页面,输入账号密码,验证成功之后,会跳转到identityservercallback页面,然后在identityservercallback页面设置路由,跳转到目标页面
这里主要讲哈前端的配置,建议看https://www.cnblogs.com/fireworkseasycool/p/10576911.html教程和oidc-client官方文档https://github.com/identitymodel/oidc-client-js/wiki
使用.Net Core + Vue + IdentityServer4 + Ocelot 实现一个简单的DEMO +源码
注意使用:自动刷新token使用自动刷新token需要accesstokenexpiringnotificationtime和automaticsilentrenew 一起设置,当accsstoken要过期前:accesstokenexpiringnotificationtime设置的时间,会去请求
identityserver4 connect/token接口,刷新token,请求到token以后会触发adduserloaded事件,我们可以把token 保存在浏览器的缓存中(cookies,localstorage)中,然后在axios中全局拦截请求,添加headers
信息
使用.Net Core + Vue + IdentityServer4 + Ocelot 实现一个简单的DEMO +源码
authorization 是token的信息,x-claims是claims的信息,传递authorization 是为了identityserver 进行验证授权,x-claims是为了后面结合ocelot,携带一些ocelot下游需要的参数进去

建立ocelotgateway项目


添加ocelot.json文件

"reroutes": [
  {
  "downstreampathtemplate": "/api/{url}",
  "downstreamscheme": "http",
  "downstreamhostandports": [
    {
      "host": "localhost",
      "port": 44375
    }
  ],
  "upstreampathtemplate": "/api/{url}",
  "upstreamhttpmethod": [ "get", "post" ],
  "priority": 2,
  "authenticationoptions": {
    "authenticationproviderkey": "identityserverkey",
    "allowscopes": [ "identityserverapi", "delimitclaim" ]
  },
  "ratelimitoptions": {
    "clientwhitelist": [  //白名单
    ],
    "enableratelimiting": true, //启用限流
    "period": "1m", 
    "periodtimespan": 30,
    "limit": 5
  },
  "qosoptions": {
    "exceptionsallowedbeforebreaking": 3,
    "durationofbreak": 3000,
    "timeoutvalue": 5000
 }

]
}


authenticationoptions 表示认证的信息:identityserver4验证信息,authenticationproviderkey 填写 addidentityserverauthentication 的key 一致,然后配置跨域,注册中间件

    services.addauthentication()
            .addidentityserverauthentication("identityserverkey", options =>
            {
                options.authority = "http://localhost:17491";
                options.apiname = "identityserverapi";
                options.supportedtokens = identityserver4.accesstokenvalidation.supportedtokens.both;
                options.requirehttpsmetadata = false;
            });
        services.addocelot()
            .addconsul()
            .addpolly();
        //配置跨域处理
        services.addcors(options =>
        {
            options.addpolicy("any", builder =>
            {
                builder.allowanyorigin() //允许任何来源的主机访问
                    .allowanymethod()
                    .allowanyheader()
                    .allowcredentials();//指定处理cookie
            });
        });
       //配置cors
        app.usecors("any");
        app.useauthentication();

program中添加

public static iwebhostbuilder createwebhostbuilder(string[] args)
    {
        return webhost.createdefaultbuilder(args)
                .configureappconfiguration((hostingcontext, config) =>
                {
                    config
                        .setbasepath(hostingcontext.hostingenvironment.contentrootpath)
                        .addocelot(hostingcontext.hostingenvironment) //ocelot合并配置文件,不能出现同样的一个端口,多个路由
                        .addenvironmentvariables();
                })
              .usestartup<startup>();
    }

学习的资料链接,参考资料

edison zhou: identityserver4和ocelot
晓晨master: identityserver4
solenovex : identityserver4 bibi上还有identityserver4视频喔
灭蒙鸟: 入门教程:js认证和webapi
.net框架学苑: ocelot 一系列教程