使用微服务架构思想,设计部署OAuth2.0授权认证框架腾讯云开发者社区

2,系统安全:采用内外网隔离的方案,一些功能需要直接暴露在公网,这需要付出额外的成本,比如带宽租用和安全设施;另外一些功能部署在内网,这样能够提供更大的安全保证。

3,易于维护:每一个服务职责都比较单一,所以每一个服务都足够小,那么开发维护就更容易,比如要更新一个功能,只需要更新一个服务而不用所有服务器都暂停;另一方面也更加容易监控服务器的负载,如果发现某一个服务器负载太大可以增加服务器来分散负载。

4,第三方接入:现在系统越来越复杂,内部的系统很可能需要跟第三方的系统对接,一起协同工作;或者整个系统一部分是。NET开发的,一部分又是Java平台开发的,两个平台部署的环境有很大差异,没法部署在一起;或者虽然同是ASP.NETMVC,但是一个是MVC3,一个是MVC5,所以需要分别独立部署。

以上就是各个服务需要分开部署的原因,而这样做的结果就是我们常说的分布式计算了,这是自然需求的结果,不是为了分而才分。

客户端直接访问后端服务,对后端的服务会形成比较强的依赖。有架构经验的朋友都知道,解决依赖的常见手段就是添加一个中间层,客户端依赖于这个中间层而不是直接依赖于服务层。这样做有几个很大的好处:

另一方面,当后端服务部署为多个独立的进程/服务器后,客户端直接访问这些服务,将是一个更加较复杂的问题,负载均衡,主备切换,灰度发布等运维功能更难操作,除此之外,还有下面两个比较重要的问题:

所以,为了解决客户端对后端服务层的依赖,并且解决后端服务太多以后引起的问题,我们需要在客户端和后端服务层之间添加一个中间层,这个中间层就是我们的服务代理层,也就是我们后面说的服务网关代理(WebAPIGatewayProxy),它作为我们所有Web访问的入口站点,这就是上图所示的WebPort。有了网关代理,后台所有的WebAPI都可以通过这个统一的入口提供对外服务的功能,而对于后端不同服务地址的路由,由网关代理的路由功能来实现,所以这个代理功能很像Nginx这样的反向代理,只不过,这里仅仅代理WebAPI,而不是其它Web资源。

经过上面的设计,我们发现这个架构有几个特点:

微服务最早由MartinFowler与JamesLewis于2014年共同提出,微服务架构风格是一种使用一套小服务来开发单个应用的方式途径,每个服务运行在自己的进程中,并使用轻量级机制通信,通常是HTTPAPI,这些服务基于业务能力构建,并能够通过自动化部署机制来独立部署,这些服务使用不同的编程语言实现,以及不同数据存储技术,并保持最低限度的集中式管理。所以我们这个架构是基本符合微服务思想的,它的诞生背景也是要解决其它传统单体软件项目现在遇到的问题一样的,是在比较复杂的实际需求环境下自然而然的一种需求,不过好在它没有过多的“技术债务”,所以设计实施起来比较容易。下面我们来详细看看这个架构是如何落地的。

简单来说,密码模式的步骤如下:

上面这个步骤只是说明了令牌的获取过程,也就是我们常说用户登陆成功的过程。当用户登陆成功之后,客户端得到了一个访问令牌,然后再使用这个令牌去访问资源服务器,具体说来还有如下后续过程:

下面是流程图:

仅仅从这两个词的名词定义可能不太容易分辨,我们用实际的例子来说明他们的区别:

PS:大家觉得好,先点个赞支持下,谢谢!

克隆我这个DEMO到本地,下面开始我们OAuth2.0如何落地的正式讲解。

首先看到解决方案视图,先逐个做下简单说明:

编号

角色

程序集名称

说明

1

PWMIS.OAuth2.AuthorizationCenter

2

资源服务器

Demo.OAuth2.WebApi

提供API资源ASP.NETWebAPI+OWIN

3

客户端

Demo.OAuth2.ConsoleTest

控制台测试程序,测试令牌申请等功能

Demo.OAuth2.WinFormTest

4

API代理网关

Demo.OAuth2.Port

用户的Web入口,本测试程序入口ASP.NETMVC5.0

5

认证服务器

Demo.OAuth2.IdentityServer

Demo.OAuth2.Mvc

6

其它

PWMIS.OAuth2.Tools

提供OAuth2.0协议访问的一些有用的工具类

然后就可以看到下面的界面:

点击确定,进入了业务操作页面,如下图:

如果能够看到这个页面,我们的OAuth2.0演示程序就成功了。下面我们来看看各个程序集项目的构建过程。

首先添加一个MVC5项目PWMIS.OAuth2.AuthorizationCenter,然后添加如下包引用:

Microsoft.AspNet.MvcMicrosoft.Owin.Host.SystemWebMicrosoft.Owin.Security.OAuthMicrosoft.Owin.Security.Cookies然后在项目根目录下添加一个OWin的启动类Startup:

varidentityRepository=IdentityRepositoryFactory.CreateInstance();这里会用到一个验证客户端的接口,包括验证用户名和密码的方法一起定义了:

namespacePWMIS.OAuth2.AuthorizationCenter.Repository{publicclassAuthDbContext:DbContext{publicAuthDbContext():base("OAuth2"){}protectedoverrideboolCheckAllTableExists(){base.CheckTableExists();base.CheckTableExists();returntrue;}}}3.3.2,认证用户,生成访问令牌生成访问令牌需要重写OWINOAuthAuthorizationServerProvider类的GrantResourceOwnerCredentials方法(方法的详细内容看前面【OpenAuthorizationServerProvider的定义】),方法里面使用到了IdentityService对象,它有一个UserLogin方法,用来实现或者调用用户认证服务:

看到OAuthClient.cs文件的OAuthClient类的GetToken方法:

首先看到PWMIS.OAuth2.Tools.TokenManager文件的CreateToken生成令牌的方法:

然后看TakeToken方法,它首先尝试获取一个当前用户的令牌,如果令牌快过期,就尝试刷新令牌:

项目Demo.OAuth2.Port在本解决方案里面有3个作用:

这里我们着重讲解第3点功能,网关代理功能另外详细介绍。

如果是ASP.NETMVC5,我们可以拦截API请求的DelegatingHandler处理器,我们定义一个AuthenticationHandler类继承它来处理:

下面我们以某个比较老的管理系统来举例,它基于ASP.NETMVC3定制开发,扩展了一些底层的东西,所以没法升级到兼容支持ASP.NETWebAPIMVC5。

首先我们来看看代理的配置文件ProxyServer.config:

需要注意的是,路由项目的匹配不是匹配到该项目后就结束,而是会尝试匹配所有路由项目,进行多次匹配和替换,直到不能匹配为止,所以代理配置文件对于路由项目的顺序很重要,也不宜编写太多的路由配置项目。

目前,支持的路由项目的API前缀地址,有/api,/api2,api3/三大种,更多的匹配前缀需要修改代理服务的源码。

首先定义一个拦截器ProxyRequestHandler,它继承自WebAPI的DelegatingHandler,可以在底层拦截对API调用的消息,在重载的SendAsync方法内实现访问请求的处理:

publicclassProxyRequestHandler:DelegatingHandler{///

///拦截请求//////请求///用于发送取消操作信号///protectedasyncoverrideTaskSendAsync(HttpRequestMessagerequest,CancellationTokencancellationToken){//实现暂略}}首先,我们需要从request请求对象中拿出当前请求的URL地址,处理代理规则,进行路由项目匹配:

if(!matched){returnawaitbase.SendAsync(request,cancellationToken);}如果匹配到,那么进入GetNewResponseMessage方法进一步处理请求:

最后,就是我们真正的代理请求访问的方法ProxyReuqest了:

privateasyncTaskProxyReuqest(HttpRequestMessagerequest,stringurl,HttpClientclient){HttpResponseMessageresult=null;if(request.Method==HttpMethod.Get){result=awaitclient.GetAsync(url);}elseif(request.Method==HttpMethod.Post){result=awaitclient.PostAsync(url,request.Content);}elseif(request.Method==HttpMethod.Put){result=awaitclient.PutAsync(url,request.Content);}elseif(request.Method==HttpMethod.Delete){result=awaitclient.DeleteAsync(url);}else{result=SendError("PWMISASP.NETProxy不支持这种Method:"+request.Method.ToString(),HttpStatusCode.BadRequest);}result.Headers.Add("Proxy-Server",this.Config.ServerName);returnresult;}4.3,注册代理拦截器和API路由前面定义了拦截器ProxyRequestHandler,现在需要把它注册到API的请求管道里面去,看到项目的WebApiConfig文件:

privateHttpClientGetHttpClient(UribaseAddress,HttpRequestMessagerequest,boolsessionRequired){if(sessionRequired){//注意:应该每个浏览器客户端一个HttpClient实例,这样才可以保证各自的会话不冲突varclient=getSessionHttpClient(request,baseAddress.Host);setHttpClientHeader(client,baseAddress,request);returnclient;}else{stringkey=baseAddress.ToString();if(dictHttpClient.ContainsKey(key)){returndictHttpClient[key];}else{lock(sync_obj){if(dictHttpClient.ContainsKey(key)){returndictHttpClient[key];}else{varclient=getNoneSessionHttpClient(request,baseAddress.Host);setHttpClientHeader(client,baseAddress,request);dictHttpClient.Add(key,client);returnclient;}}}}}上面的代码,根据URL请求的基础地址(被代理访问的目标主机地址)为字典的键,获取或者添加一个HttpClient对象,创建新HttpClient对象使用下面这个方法:

privateHttpClientgetNoneSessionHttpClient(HttpRequestMessagerequest,stringhost){HttpClientclient=newHttpClient();client.DefaultRequestHeaders.Connection.Add("keep-alive");returnclient;}这个方法主要作用是为新创建的HttpClient对象添加长连接请求标头。

另外,还需要解决DNS缓存问题,在ServicePointManager类进行设定,每一分钟刷新一次。

//定期清除DNS缓存varsp=ServicePointManager.FindServicePoint(baseAddress);sp.ConnectionLeaseTimeout=60*1000;//1分钟最后,修改默认的并发连接数为512,如下:

我们的入口网站(WebPort)一般都是支持会话的,有时候,需要在资源服务器或者认证服务器保持用户的会话状态,提供有状态的服务。前面我们说明实现代理访问使用了HttpClient对象,默认情况下同一个HttpClient对象与服务器交互是可以保持会话状态的,在代理请求的时候,将原始请求的Cookie值附加到代理请求的HttpCliet的CookieContainer对象即可。然而为了优化HttpClient的访问效率,我们对同一个被代理访问的资源服务器使用了同一个HttpClient对象,而不是对同一个浏览器的请求使用同一个HttpClient对象。实际上,并不需要这样做,只要确保当前HttpClient对象的Cookie能够发送到被代理的资源服务器即可,针对每个请求线程创建一个HttpClient对象实例是最安全的做法。

回到前面的GetHttpClient方法,看到下面代码:

if(sessionRequired){//注意:应该每个浏览器客户端一个HttpClient实例,这样才可以保证各自的会话不冲突varclient=getSessionHttpClient(request,baseAddress.Host);setHttpClientHeader(client,baseAddress,request);returnclient;}在getSessionHttpClient方法中,将原始请求的Cookie值一一复制到新的请求上去。CookieContainer里面的Cookie跟HttpRequestMessage请求头里面的Cookie根本就不是一回事,需要一个个的转换:

privateHttpClientgetSessionHttpClient(HttpRequestMessagerequest,stringhost){CookieContainercc=newCookieContainer();HttpClientHandlerhandler=newHttpClientHandler();handler.CookieContainer=cc;handler.UseCookies=true;HttpClientclient=newHttpClient(handler);//复制CookiesvarheaderCookies=request.Headers.GetCookies();foreach(varchvinheaderCookies){foreach(variteminchv.Cookies){Cookiecookie=newCookie(item.Name,item.Value);cookie.Domain=host;cc.Add(cookie);}}returnclient;}我们知道对于ASP.NET来说,服务器支持会话是因为服务器给客户端发送了一个名字为ASP.NET_SessionId的Cookie,只要这个Cookie发送过去了,被代理的服务器就不会再为“客户端”生成这个会话ID,并且会使用这个会话ID,在当前服务器(资源服务器)维护自己的会话状态。

注意:虽然WebPort跟被代理的服务器使用了一样的SessionID,但它们的会话状态并不相同,只不过看起来访问两个服务器的客户端(浏览器)是同一个而已。

这样,我们就间接的实现了资源服务器“会话状态”的代理。

默认情况下,我们并不会对所有请求使用有会话状态的代理,而是使用优化了连接请求的代理,如果需要启用代理会话状态的功能需要设置SessionRequired为true,具体请参考下面的【5.2,代理获取验证码的API】

\PWMIS.OAuth2\Demo.OAuth2.Port\Views\Logon\Index.cshtml

由于验证服务器(地址:【localhost:50697】)验证码功能是使用Session存储的,所以需要在代理配置文件(ProxyServer.config)中的代理路由配置项目添加会话支持,

指定SessionRequired属性为true,如下所示:

看到示例的认证服务器项目Demo.OAuth2.Mvc,在控制器LoginController添加一个Action,随机生成6位数字验证码,然后存储在当前服务器的会话状态中:

在OAuthClient工具类中,我们封装了一个可以包含验证码的请求生成验证码的方法:

如果你打算在你的软件项目中也使用OAuth2.0的密码认证方案,PWMIS.OAuth2.0可以作为一个样例解决方案,你可以直接使用,做好API的代理配置即可,不论你的API是不是.NET开发的。

PWMIS.OAuth2.0是一个开源项目,可以直接在你项目使用。如果有问题,请在本文回帖留言,感谢大家支持!

THE END
1.新产品(名词解释)【答案】:是指企业向市场提供的,相对于旧产品,在产品结构、性能、用途等某一方面或几方面满足顾客新的需求的产品。https://zhidao.baidu.com/question/884065078523420212.html
2.什么是新产品,名词解释定义是?参考答案:标准实物量是在经济用途相同,而品种、规格、含量不同的同类产品中,确定某种产品作为标准产品,将其他产品产量按一定比例折算标 点击查看答案进入题库练习 名词解释 物质产品 参考答案: 物质产品又称实物产品或有形产品,是指企业生产活动的结果,创造了新的实物形态和新的使用价值的产品。 点击查看答案进入https://m.ppkao.com/mip/tiku/shiti/6344292.html
3.名词解释:新产品扩散名词解释:新产品扩散学历类问答题,自考问答题,自考专业(营销)问答题,市场营销策划问答题https://www.chazidian.com/kaoshi/shiti-162219/
4.名词解释:新产品扩散名词解释:新产品扩散学历类问答题,自考问答题,自考专业(营销)问答题,市场营销策划问答题http://m.xiaokaoku.com/shiti-162219/
5.市场营销学考试复习6篇(全文)一、名词解释 1.撇脂定价策略:是指企业在新产品刚刚投放市场时把价格定得很高,以求在尽可能短期限内迅速获取高额利润的价格策略。 2.产品组合:是指某一特定销售者所能提供给消费者的一整套产品和产品项目。 3.品牌:是指用来识别卖者的产品和劳动的名称、符号、象征、设计或是它们的组合所构成,用来区别本企业与https://www.99xueshu.com/w/file0wu7cgxt.html
6.销售管理自考《市场营销学》(三)湖南工商大学自考1、市场细分(名词解释):就是企业根据自身条件和营销目标,以需求的某些特征或变量为依据,区分具有不同需求的顾客群体的过程。 市场细分是1956年由美国营销学者温德尔·斯密于《产品差异和市场细分---可供选择的两种市场营销战略》一文中,在总结西方企业营销实践经验的基础上提出的。 2http://www.hnsxyzk.org/ziliaoxiazai/zkzl/2013/1114/588.html
7.市场营销一、名词解释 1、市场是指产品或者服务的现实或者潜在购买者的集合。 2、市场营销是指对产品和服务进行设计、定价、促销、分销的计划和实施的一系列过程,从而产生满足个人和组织目标的交换的结果。 3、市场营销环境是指企业的生存空间是企业开展营销活动的基础和条件,是作用于企业营销的外部条件的力量总和。 http://www.360doc.com/content/12/0223/17/8035336_189057606.shtml
8.市场营销学试题(6)及答案(精选6篇)五、名词解释(每小题3分,共12分。) 1、市场营销管理 答:市场营销管理是指企业为实现其目标,创造、建立并保持与目标市场之间的互利交换关系而进行的分析、计划、执行与控制过程。 2、市场总需求 答:某一产品的市场总需求,是指在一定的营销努力水平下,一定时期内在特定地区、特定营销环境中,特定顾客群体可能购买的https://www.360wenmi.com/f/file8m75sh3k.html
9.名词解释新产品试制费新产品试制费是为试制新产品而支付的各项试制费用,以及为试制需要而增加的非主要固定资产的支出。包括:(1) 新产品试制准备工作发生的各项费用 (如设计费、工艺规程制定费、设备调整费、增添的非主要设备的购建成本、专用工卡具费、产品试验费以及样品样机购制费等);(2) 试制成功作为商品产品的实际成本大于售价的https://www.shuashuati.com/ti/d76b3db40254487886239904d3f05562.html