.net core使用ocelot---第二篇 身份验证
简介
接上文,我将继续介绍使用asp.net core 创建api网关,主要介绍身份验证(authentication )相关内容。
api服务是需要保护的资源,我们应该尽可能的保证他们的安全。
通常,我们会使用aspnet security 来保证我们项目的安全,aspnet security代码库是为asp.net core 设计的安全和授权中间件。已经让事情变得简单。
那么我们在项目中引入api网关会不会导致巨大的改变?答案是,不会。我们的修改微乎其微,但是却让安全和授权变得简单。
先看下面的截图。
截图显示,当我们访问我们的服务,api网关会让我们首先访问其授权模块。我们必须访问授权服务获得访问令牌(access token),然后用访问令牌访问受保护的服务。
可能你倾向将授权服务独立,这意味客户端得先访问授权服务获得访问令牌。然后携带令牌访问api网关。毫无疑问这样做没问题,但是我建议将授权服务和其他服务放在一起。
apigateway是我们所有服务的入口,对于身份未验证的客户端仅可以访问授权服务。
ok,开始我们的表演。
我会使用上一个demo的部分内容,便于理解。
step1
项目名称 |
项目类型 |
描述 |
apigateway |
asp.net core empty |
示例的入口 |
customersapiservices |
asp.net core web api |
api 服务处理消费者的操作 |
authserver |
asp.net core web api |
api 服务处理授权操作 |
clientapp |
console app |
控制台程序模拟客户端 |
apigateway和customerapiservices和上篇文章的例子一样,你可以在apigatewaybasicdemo获得。
step2
创建authserver,authserver主要是为request请求生成访问令牌(access token),我们需要添加一个方法处理。
[httpget] public iactionresult get(string name, string pwd) { //just hard code here. if (name == "catcher" && pwd == "123") { var now = datetime.utcnow; var claims = new claim[] { new claim(jwtregisteredclaimnames.sub, name), new claim(jwtregisteredclaimnames.jti, guid.newguid().tostring()), new claim(jwtregisteredclaimnames.iat, now.touniversaltime().tostring(), claimvaluetypes.integer64) }; var signingkey = new symmetricsecuritykey(encoding.ascii.getbytes(_settings.value.secret)); var tokenvalidationparameters = new tokenvalidationparameters { validateissuersigningkey = true, issuersigningkey = signingkey, validateissuer = true, validissuer = _settings.value.iss, validateaudience = true, validaudience = _settings.value.aud, validatelifetime = true, clockskew = timespan.zero, requireexpirationtime = true, }; var jwt = new jwtsecuritytoken( issuer: _settings.value.iss, audience: _settings.value.aud, claims: claims, notbefore: now, expires: now.add(timespan.fromminutes(2)), signingcredentials: new signingcredentials(signingkey, securityalgorithms.hmacsha256) ); var encodedjwt = new jwtsecuritytokenhandler().writetoken(jwt); var responsejson = new { access_token = encodedjwt, expires_in = (int)timespan.fromminutes(2).totalseconds }; return json(responsejson); } else { return json(""); } }
在验证用户时。我使用硬编码将用户名写死,因为对于本文这个不是那么重要。
这样我们就完成了授权服务,现在跑起来。
step3
回到customersapiservices项目,我们应该保护这个服务。
修改startup,我们可以使用授权。在这我用jwtbearer进行授权,我会给testkey设置默认的授权方案。testkey我将在下面提到。
public void configureservices(iservicecollection services) { var audienceconfig = configuration.getsection("audience"); var signingkey = new symmetricsecuritykey(encoding.ascii.getbytes(audienceconfig["secret"])); var tokenvalidationparameters = new tokenvalidationparameters { validateissuersigningkey = true, issuersigningkey = signingkey, validateissuer = true, validissuer = audienceconfig["iss"], validateaudience = true, validaudience = audienceconfig["aud"], validatelifetime = true, clockskew = timespan.zero, requireexpirationtime = true, }; services.addauthentication() .addjwtbearer("testkey", x => { x.requirehttpsmetadata = false; x.tokenvalidationparameters = tokenvalidationparameters; }); services.addmvc(); } public void configure(iapplicationbuilder app) { app.useauthentication(); app.usemvc(); }
接下来,对需要保护的方法,添加authorize。
[authorize] [httpget] public ienumerable<string> get() { return new string[] { "catcher wong", "james li" }; }
注意
该项目基于asp.net core 2.0. 如果你的项目是1.x,可能有些不同,建议用迁移到2.0.以上。接下来就是见证奇迹的时候了。
step4
最重要的步骤来了,在apigateway中配置授权。
public void configureservices(iservicecollection services) { var audienceconfig = configuration.getsection("audience"); var signingkey = new symmetricsecuritykey(encoding.ascii.getbytes(audienceconfig["secret"])); var tokenvalidationparameters = new tokenvalidationparameters { validateissuersigningkey = true, issuersigningkey = signingkey, validateissuer = true, validissuer = audienceconfig["iss"], validateaudience = true, validaudience = audienceconfig["aud"], validatelifetime = true, clockskew = timespan.zero, requireexpirationtime = true, }; services.addauthentication() .addjwtbearer("testkey", x => { x.requirehttpsmetadata = false; x.tokenvalidationparameters = tokenvalidationparameters; }); services.addocelot(configuration); }
这个配置的大部分代码和customer service一样。
当ocelot启动,它会查看reroutes 》authenticationoptions 》authenticationproviderkey 的值,
检查该值是否被授权服务注册,如果没有,ocelot不会启动,如果有,ocelot在执行时使用授权服务。
所以,我们得修改configuration.json,我们需要添加新的节点,并将其值赋为在startup 类中定义的一样。
{ "downstreampathtemplate": "/api/customers", "downstreamscheme": "http", "downstreamhost": "localhost", "downstreamport": 9001, "upstreampathtemplate": "/customers", "upstreamhttpmethod": [ "get" ], "authenticationoptions": { "authenticationproviderkey": "testkey", "allowedscopes": [] } }
启动服务。
注意
当你启动项目时遇到下面的错误,你应该检查你的代码,查看addjwtbearer 方法是否指明授权方案。
unhandled exception: system.invalidoperationexception: scheme already exists: bearer
step5
我们已经准备完毕,我们用我们的客户端模拟apigateway的某些请求。
我们先添加获得访问令牌的方法。
private static string getjwt() { httpclient client = new httpclient(); client.baseaddress = new uri( "http://localhost:9000"); client.defaultrequestheaders.clear(); var res2 = client.getasync("/api/auth?name=catcher&pwd=123").result; dynamic jwt = jsonconvert.deserializeobject(res2.content.readasstringasync().result); return jwt.access_token; }
接下来,编写通过apigateway访问customer service方法的代码。
static void main(string[] args) { httpclient client = new httpclient(); client.defaultrequestheaders.clear(); client.baseaddress = new uri("http://localhost:9000"); // 1. without access_token will not access the service // and return 401 . var reswithouttoken = client.getasync("/customers").result; //print something here //2. with access_token will access the service // and return result. client.defaultrequestheaders.clear(); var jwt = getjwt(); client.defaultrequestheaders.add("authorization", $"bearer {jwt}"); var reswithtoken = client.getasync("/customers").result; //print something here //3. visit no auth service client.defaultrequestheaders.clear(); var res = client.getasync("/customers/1").result; //print something here console.read(); }
运行结果。
完工。
源码在此。
总结
没啥。
推荐阅读
-
ASP.Net Core中使用枚举类而不是枚举的方法
-
Asp.net Core中如何使用中间件来管理websocket
-
.Net Core中使用Quartz.Net实践记录
-
ASP.NET Core部署前期准备 使用Hyper-V安装Ubuntu Server 16.10
-
创建基于ASP.NET core 3.1 的RazorPagesMovie项目(一)-创建和使用默认的模板
-
使用NuGet将我们的ASP.NET Core类库打包并将程序包(类库)发布到NuGet平台上进行管理
-
[笔记]使用Docker部署.NET Core应用程序
-
使用ASP.NET Core 3.x 构建 RESTful API - 5.1 输入验证
-
详解Asp.net Core 使用Redis存储Session
-
建议收藏:.net core 使用EPPlus导入导出Excel详细案例,精心整理源码已更新至开源模板