IIS7.5之ApplicationPoolIdentify详解

ApplicationPoolIdentify 在 Windows Server 2008 和 Windows Vista 的 Service Pack 2(SP2)和更高版本的Windows引入的强大的新隔离功能,IIS7.5中首次引用。其它三种包括 LocalService , LocalSystem,NetWorkService

ApplicationPoolIdentify 允许在唯一帐户下运行应用程序池,而无需创建和管理域或本地帐户。应用程序池帐户的名称对应于应用程序池的名称。

下图显示了作为DefaultAppPool标识运行的IIS工作进程(W3wp.exe)。

image3.jpg

Windows操作系统提供称为“虚拟帐户”的功能,允许IIS为其每个应用程序池创建唯一标识。

配置IIS ApplicationPoolIdentify

如果在Windows Server 2008 R2或更高版本的IIS上运行IIS 7.5,则无需执行任何操作即可使用新标识。创建的每个应用程序池,默认情况下,新应用程序池的Identity属性设置为ApplicationPoolIdentity。IIS管理进程(WAS)将创建一个具有新应用程序池名称的虚拟帐户,并默认在此帐户下运行应用程序池的工作进程。

要在Windows Server 2008上运行IIS 7.0时使用此虚拟帐户,必须将创建的应用程序池的Identity属性更改为ApplicationPoolIdentity

方法:

1,打开IIS管理控制台(INETMGR.MSC)
2,打开计算机节点下的“应用程序池”节点。选择要更改为在自动生成的应用程序池标识下运行的应用程序池。
3,右键单击应用程序池,然后选择高级设置。

image6.jpg

4,选择标识列表项,然后单击省略号(带有三个点的按钮)。
5,出现以下对话框

image8.jpg

6,选择内置帐户按钮,然后从组合框中选择标识类型ApplicationPoolIdentity。

要使用命令行执行相同的步骤,可以通过以下方式调用appcmd命令行工具:

1
%windir%\system32\inetsrv\appcmd.exe set AppPool <your AppPool> -processModel.identityType:ApplicationPoolIdentity

确保资源安全

每当创建新的应用程序池时,IIS管理进程都会创建一个安全标识符(SID),该标识符表示应用程序池本身的名称。例如,如果创建名为“MyNewAppPool”的应用程序池,则会在Windows安全系统中创建名为“MyNewAppPool”的安全标识符。从现在开始,可以使用此标识来保护资源。但是,身份不是真实的用户帐户; 它不会在Windows用户管理控制台中显示为用户。

我们可以通过在Windows资源管理器中选择一个文件并将“DefaultAppPool”标识添加到文件的访问控制列表(ACL)来尝试此操作。

1,打开Windows资源管理器
2,选择文件或目录。
3,右键单击该文件并选择”属性”
4,选择”安全”选项卡
5,单击编辑按钮,然后单击添加按钮
6,单击”位置”按钮,确保选择计算机。

image11.jpg

7,在输入要选择的对象名称:文本框中输入 IIS AppPool\DefaultAppPool
8,单击”检查名称”按钮,然后单击“ 确定”。

参考:

Application Pool Identities

IIS ApplicationPoolIdentity

IIS7.5中神秘的ApplicationPoolIdentity

Chrome插件记录

uBlock Origin

链接:uBlock Origin

一款高效的网络请求过滤工具,占用极低的内存和 CPU。

Tampermonkey

链接:Tampermonkey

中文俗称油猴,它其实是一个脚本仓库,提供了各式各样的脚本,通过这些脚本,可以完成很多强大的功能,比如去广告,下载百度云盘大文件。

GitCodeTree

链接:GitCodeTree

一个浏览器插件,在Gitee、GitHub上显示代码树。不用clone到本地就能查看项目结构。

Postman

链接:Postman

这是一款强大的 API & HTTP 请求调试工具,它不仅可以调试简单的 HTML、CSS 以及脚本等简单的网页基本信息,这款 Chrome 插件甚至还能发送几乎所有的 HTTP 请求,可谓是 Web 开发者的一大利器。

WEB前端助手(FeHelper)

链接:WEB前端助手(FeHelper)

阅读模式

链接:阅读模式

Git History Browser Extension

链接:Git History Browser Extension

在 GitHub 中,显示任意一个文件的历史修改情况。

二维码生成器

链接:二维码生成器 (Quick QR)

可以将输入的任何内容转换成二维码图片,图片可以保存,并且无需联网。

翻译侠

链接:翻译侠(Translate Man)

Chromoji - Emoji

链接:Chromoji - Emoji

表情工具。

喵喵折+

链接:喵喵折+

购物比价神器,对比一件商品现在的价格比历史价格是高还是低。

购物党自动比价工具

链接:购物党自动比价工具

在线的比价工具,网购的时候可以看价格历史记录,以及各大网站的价格对比,也有查快递的快捷方式。

图流-看图助手

链接:图流-看图助手

能够以列表的形式将所有图片展现。

谷歌访问助手

链接:谷歌访问助手

可以科学访问谷歌。

高效网页截图编辑

截取任意网页,可以像画图软件那样用直线、箭头、圆圈、文字做出标识。并可以方便的通过链接或者附件分享。

JSONViewer

一个窗口格式化多条JSON,提高开发效率。

Ultimate Video Downloader

保存视频和音频变得简单。

Chrono下载管理器

做Chrome浏览器中最好的下载管理器。

Fatkun图片批量下载

找出当前页面的所有图片,提供按分辨率、链接等筛选图片,做一个简单好用的下载图片扩展!

Save to Pocket

链接:Save to Pocket

看到感兴趣的先收藏着,然后走哪儿都能看,因为它提供了全平台的APP,方便管理。

WhatRuns

链接:WhatRuns

WhatRuns是一款用于了解网站技术的chrome网站技术分析工具,主要能通过分析网站页面所使用的框架、代码等技术以及页面所使用的样式等方面,让使用者能直观的了解网站的整体技术信息。在安装了这款插件后,使用者可以通过点击WhatRuns图标来打开插件窗口,通过该窗口使用者可以轻松了解网站的技术信息

Code Cola

链接:Code Cola

Code Cola是一个可视化编辑在线页面css样式的chrome插件。

Lucidchart 离线图表

链接:Lucidchart 离线图表

这个扩展程序是一款多功能绘制程序,支持绘制流程图,思维导图,版面设计等,并且有在线和离线两种模式,可谓功能强大。

Clear Cache

链接:Clear Cache

点击图标即可清除缓存、cookie等,开发必备!

参考:

这些好用的 Chrome 插件,提升你的工作效率

chrome tools

实用且堪称神器的Chrome插件推荐

有哪些鲜为人知却非常有意思、好用的 Chrome 扩展?

你极力推荐的 Chrome 扩展有哪些?

https://www.crx4chrome.com/

Resharper工具之Stack Trace Explorer使用

Stack Trace Explorer 显示剪贴板中的堆栈跟踪,并将其中的行转换为可单击的链接,可以直接导航到相关代码。

使用:

1,复制需要调试跟踪的代码,

2,打开Resharper-> Tools -> Browse Stack Trace

微信截图_20190416105942.png

参考:

Stack Trace Explorer

解决ssh-keygen不是内部或外部命令

使用Git生成SSH密钥时,cmd报错:ssh-keygen不是内部或外部命令。

解决:

1,设置环境变量(推荐方法)

找到系统->高级系统设置->找到高级-> 环境变量-> 找到Path变量->选择编辑-添加ssh-keygen.exe路径,如下图:

微信截图_20190411163954.png

2,找到Git/usr/bin目录下的ssh-keygen.exe

参考:

ssh-keygen不是内部或外部命令

统一建模语言UML

简介

统一建模语言(英语:Unified Modeling Language,缩写 UML)是非专利的第三代建模和规约语言。UML是一种开放的方法,用于说明、可视化、构建和编写一个正在开发的、面向对象的、软件密集系统的制品的开放方法。UML展现了一系列最佳工程实践,这些最佳实践在对大规模,复杂系统进行建模方面,特别是在软件架构层次已经被验证有效。

模型

在UML系统开发中有三个主要的模型:

  • 功能模型:从用户的角度展示系统的功能,包括用例图。
  • 对象模型:采用对象,属性,操作,关联等概念展示系统的结构和基础,包括类别图、对象图。
  • 动态模型:展现系统的内部行为。包括序列图,活动图,状态图。

图形

结构性图形(Structure diagrams)

1,静态图(static diagram

  • 类图
  • 对象图
  • 包图

2,实现图(implementation diagram)

  • 组件图
  • 部署图

行为式图形(Behavior diagrams)

  • 活动图
  • 状态图
  • 用例图

交互性图形(Interaction diagrams)

  • 通信图
  • 交互概述图(UML 2.0)
  • 时序图(UML 2.0)
  • 时间图(UML 2.0)

UML类图

属性和方法

在UML类图中,类使用包含类名、属性(field) 和方法(method) 且带有分割线的矩形来表示。

UML类图中表示可见性的符号有三种:

1
2
3
+ :表示public
- :表示private
# :表示protected(friendly也归入这类)

规则:可见性 名称 :类型 [ = 缺省值]

微信截图_20190401142800.png

对象关系

关联关系

1,单项关联

单向关联用一个带箭头的直线表示。

617148-20160612224805636-1840590061.jpg

2,双向关联

双向关联就是双方各自持有对方类型的成员变量,双向关联用一个不带箭头的直线表示。

617148-20160612225006840-13774319.jpg

3,自关联

617148-20160612225239636-76459111.jpg

聚合关系

UML中聚合关系用带空心菱形和箭头的直线表示,空心菱形能分离而独立存在。

617148-20160612225421496-664373564.jpg

组合关系

UML类图中组合关系用一个带实心菱形和箭头的直线表示。

617148-20160612232819824-829657559.jpg

依赖关系

在UML类图中依赖关系用一条带有箭头的虚线表示。

617148-20160612232951746-9292157.jpg

继承父类

在UML类图中继承父类用一条带有三角的实线表示。

617148-20160612233246199-1404301867.jpg

继承接口

在UML类图中继承接口用一条带有三角的虚线表示。

617148-20160612233430777-736506858.jpg

参考:

统一建模语言

一张图读懂UML

五分钟读懂UML类图

vs2013\2015UML系列之-类图

ASP.NET Web API 2.0学习笔记

概述

ASP.NET Web API是一个独立于传输层的抽象消息处理管道,它能根据请求采用 HTTP方法来确定目标 Action方法。
IIS 默认拒绝PUTDELETE请求,原因是默认注册了 WebDAVModule,可以通过配置文件移除HttpModule

** Web API的宿主方式**
1,web host 方式
以 Web Host的 方式寄宿 Web API需 要做的唯——件事情是路 由注册。

2,self host 方式
任意类型的应用程序 (控制台、Windows Forms应 用、WPF应用甚至是 Windows sewioc)作为宿主。
除了必须的路 由注册外,我们还需要完成额外的一件事情,即手工加载定义了HttpController类型的程序集。

路由

ASP.NET路由系统

一个Web 应用具有一个全局的路由表,通过 System.Web.Routing.RouteTable的静态属性Routes表示。

RouteBase

一个Route继承抽象类System.Web.Routing.RouteBase

RouteData

VirTalPathData

Route
System.Web.Routing.Route是抽象类System.Web.Routing.RouteBase唯一的直接子类,基于路由模版模式的路由匹配规则就定义在Route中。

RouteTable

ASP.NET WEB API 路由

请求与响应

ASP.NET WEB API通过类型HttpRequestMessageHttpResponseMessage表示的管道处理的请求和响应的消息,定义在System.Net.Http.dll中。

HttpRequestMessage

HttpResponseMessage

HttpContent

ASP.NET WEB API 路由系统

ASP.NET WEB API路由系统中HostedHttpRoute对象通过创建ASP.NET路由系统中的HttpWebRoute对象进行路由解析。
针对约束的检查则依然是ASP.NET WEB API路由系统中的HttpRouteConstraint

Web Host宿主模式采用的route类型为HttpWebRoute,对应的RouteHandlerHttpControllerRouteHandler对象,提供的HttpHandler类型为HttpControllerHandler

ASP.NET WEB API以Web Host模式部署并注册相应的路由后,这些注册的HttpRoute(HostedHttpRoute)最终会转换成asp.net全局路由表中的Route(HttpWebRoute)
asp.net路由系统对请求进行拦截,如果匹配某个Route,响应的路由数据
被解析出来并保存在RequestContext中,随后asp.net路由系统的实现者
UrlRoutingModule从匹配的Route中获取RouteHandler,即HttpControllerRouteHandler对象,该对象提供HttpHandler(HttpControllerHandler)被映射到当前请求。
一旦映射成功,HttpControllerHandler将最终接管当前请求,它会构建一个
消息处理管道来处理这个请求并对请求予以响应。

HttpControllerHandler创建HttpRequestMessage,并将ASP.NET路由系统解析得到的RouteData转换成HttpRouteData,并添加到HttpRequestMessage属性的字典中。

HttpRouteData

HttpVirtualPathData

HttpRouteConstraint

HttpRoute

HttpRouteCollection

HostedHttpRoute
可以看成一个对Route对象的封装。

消息处理管道

ASP.NET WEB API的核心框架是一个消息处理管道,由一组HttpMessageHandler的有序组合。

1, HttpMessageHandler
ASP.NET WEB API的核心框架是一个消息处理管道,由一组HttpMessageHandler经过收尾相连而成。

2,DelegatingHandler

管道的串联通过DelegatingHandler来完成。

3,HttpServer

作为HttpMessageHandler链的龙头

4,HttpRoutingDispatcher

消息处理管道最后一个HttpMessageHandler.
主要功能:路由(Routing)和消息分发(Dispatching)
默认从HttpRoutingDispatcher接管请求的HttpMessageHandlerHttpControllerDispatcher对象。对HttpController的激活和Action方法的执行和响应都是有HttpControllerDispatcher完成的。

Web Host模式下消息处理管道

HttpControllerHandler

HttpControllerHandler创建HttpRequestMessage,并将ASP.NET路由系统解析得到的RouteData转换成HttpRouteData,并添加到HttpRequestMessage属性的字典中。

Self Host模式下消息处理管道

HttpController的激活

HttpController

HttpRoutingDispatcher会利用隶属于它的HttpControllerDispatcher激活目标HttpController对象。

1,HttpControllerContext

HttpController对象ExecuteAsync方法得到HttpControllerContext

2,HttpControllerDescripor

HttpControllerDescriptor封装了某个HttpController类型的元数据,即HttpController类型的描述对象。

创建HttpController

HttpController如何创建的

HttpControllerDispatcher实现目标HttpController对象的激活与执行,并将代表执行结果的HttpResponseMessage对象返回给HttpRoutingDispatcher对象,后者将HttpResponseMessage回传给消息管道进行相应的处理后最终完成对请求的响应。

HttpControllerDispatcher接管请求后,它会获取注册的HttpControllerSelector对象,默认注册的HttpControllerDescriptor 是一个DefaultHttpControllerSelector,后者借助于注册的HttpControllerTypeResolver对象得到所有的HttpController类型,进而创建一个描述这些HttpControllerHttpControllerDescriptor对象与HttpController名称之间的映射关系,并调用其SelectController方法 得到描述目标HttpControllerHttpControllerDescriptor对象。

HttpControllerDispatcher接下来调用这个HttpControllerDescriptor对象的CreateController方法得到激活的HttpController对象。对于这个HttpControllerDescriptor对象来说,当它CreateController方法被调用之后,它会获取注册的HttpControllerActivator对象,并调用其Create方法实现针对目标HttpController对象的激活并将激活的对象返回。

默认注册的DefaultHttpControllerActivator对象会利用注册的DependencyResolver根据HttpController类型去获取代表目标HttpController实例的对象。如果后者返回一个HttpController对象,该对象将直接作为方法的返回值,否则DefaultHttpControllerActivator直接采用反射的形式创建目标HttpController对象并返回。

由于默认注册的DepandencyResolver是一个EmptyResolver对象,由它返回HttpController对象总是null,所以在默认情况下激活HttpController对象总是以反射的形式创建的。所以我们定义HttpController类型必须具有一个默认的构造函数。

Action的选择

HttpActionDescriptor

HttpActionDescriptor是一个抽象类。

定义在HttpController类型中的每一个Action方法都是通过HttpActionDescriptor对象来描述的。描述Action方法的基本元数据信息均可以在对应的HttpActionDescriptor对象中找到。

ReflectedHttpActionDescriptor

HttpActionDescriptor是一个抽象类,默认实现是ReflectedHttpActionDescriptor对象,通过对目标方法实施反射来获取相关的元数据信息。
一个ReflectedHttpActionDescriptor对象是对一个MethodInfo的封装,
描述Action方法相关的元数据基本来源于此。

ActionNameAttribute

应用ActionNameAttribute特性来对Action进行命名。

方法名决定HTTP方法

如果Action方法具有以下的前缀(不区分大小写),那么对应的HTTP方法将默认支持。不具有,则默认支持POST。

  • GET
  • POST
  • PUT
  • DELETE
  • HEAD
  • OPTIONS
  • PATCH

ActionHttpMethodProvider

ActionHttpMethodProvider应用到某个Action方法上,并为其提供它所支持的HTTP方法。

AcceptVerbsAttribute特性

写法:

1
[AcceptVerbsAttribute("PUT","POST")]

ASP.NET Web API 定义的7中对应的特性类型:

1
2
3
4
5
6
7
HttpGetAttribute
HttpPostAttribute
HttpPutAttribute
HttpDeleteAttribute
HttpHeadAttribute
HttpOptionsAttribute
HttpPatchAttribute

HttpParameterDescriptor

抽象类,用户描述Action方法参数的HttpParameterDescriptor对象。

ReflectedHttpParameterDescriptor

HttpActionSelector

使用ApiControllerActionSelector对象作为默认的HttpActionSelector

特性路由

参考:

[ASP.NET Web API 2 框架揭秘](ASP.NET Web API 2 框架揭秘)

单例模式涉及到的基础知识,包括静态构造函数,私有构造函数,锁,延时创建对象, readonly/const 等等。

单例的优点: 1.保证了所有的对象访问的都是同一个实例 2.由于类是由自己类控制实例化的,所以有相应的伸缩性

单例的缺点: 1.额外的系统开销,因为每次使用类的实例的时候,都要检查实例是否存在,可以通过静态实例该解决。 2.无法销毁对象,单例模式的特性决定了只有他自己才能销毁对象实例,但是一般情况下我们都没做这个事情。

阅读全文 »

OpenID Connect 协议

OpenID Connect简介

OpenID Connect是由OpenID基金会于2014年发布的一个开放标准,简称OIDC, 它使用OAuth2.0来进行身份认证,OpenID Connect是OpenID的第三代技术。 OpenID Connect直接构建于OAuth2.0的基础之上,添加了一些组件来提供身份认证的能力与其兼容。 通常OpenID Connect是和OAuth2一同部署来使用的。

OpenID Connect是更高级的协议, 它扩展并替代了OAuth2.0 尽管现在我们经常说我们在使用OAuth2.0来保护API, 其实更准确的说, 大多数情况下, 我们使用的是OpenID Connect.

身份认证(Authentication)
授权(Authorization)

名词定义

  • EU:End User,用户。

  • RP:Relying Party ,用来代指OAuth2中的受信任的客户端,身份认证和授权信息的消费方;

  • OP:OpenID Provider,有能力提供EU身份认证的服务方(比如OAuth2中的授权服务),用来为RP提供EU的身份认证信息;

  • ID-Token:JWT格式的数据,包含EU身份认证的信息。

  • UserInfo Endpoint:用户信息接口(受OAuth2保护),当RP使用ID-Token访问时,返回授权用户的信息,此接口必须使用HTTPS。

OIDC基础

OpenID是 Authentication,即认证,对用户的身份进行认证,判断其身份是否有效,也就是让网站知道“你是你所声称的那个用户”;

OAuth是 Authorization,即授权,在已知用户身份合法的情况下,经用户授权来允许某些操作,也就是让网站知道“你能被允许做那些事情”。

由此可知,授权要在认证之后进行,只有确定用户身份才能授权。
(身份验证)+ OAuth 2.0 = OpenID Connect

OpenID Connect是“认证”和“授权”的结合,因为其基于OAuth协议,所以OpenID Connect协议中也包含了client_idclient_secret还有redirect_uri等字段标识。这些信息被保存在身份认证服务器,以确保特定的客户端收到的信息只来自于合法的应用平台。这样做是目的是为了防止client_id泄露而造成的恶意网站发起的OIDC流程。

在OAuth中的scopeOpenID Connect也有自己特殊的scope--openid ,它必须在第一次请求“身份鉴别服务器”(Identity Provider,简称IDP)时发送过去。

OIDC流程

OIDC基于OAuth2,所以OIDC的认证流程主要是由OAuth2的几种授权流程延伸而来的,有以下3种:

  • Authorization Code Flow:使用OAuth2的授权码来换取Id_TokenAccess_Token
  • Implicit Flow:使用OAuth2的Implicit流程获取Id_Token和Access_Token
  • Hybrid Flow:混合Authorization Code Flow+Implici Flow

OpenID Connect抽象流程:

986268-20180627101906559-326862209.png

1
2
3
4
5
1. 依赖发(RP)发送请求到OpenID提供商(OP, 也就是身份提供商).
2. OpenID提供商验证最终用户的身份, 并获得了用户委派的授权
3. OpenID提供商返回响应, 里面带着ID_Token, 也通常带着Access_Token.
4. 依赖方现在可以使用Access_Token发送请求到用户信息的端点.
5. 用户信息端点返回用户的声明(claims, 相当于是用户的信息).

OpenID Connect身份认证有三个路径(三个流程, flow): Authorization Code, ImplicitHybrid

Authorization Code(授权码)

要求客户端应用可以安全的在它和授权服务器之间维护客户端的secret,也就是说只适合这样的客户端应用。它还适合于长时间的访问(通过refresh token)。

1
2
3
4
5
6
7
8
1,客户端准备身份认证请求, 请求里包含所需的参数
2,客户端发送请求到授权服务器
3,授权服务器对最终用户进行身份认证
4,授权服务器获得最终用户的同意/授权
5,授权服务器把最终用户发送回客户端, 同时带着授权码
6,客户端使用授权码向Token端点请求一个响应
7,客户端接收到响应, 响应的body里面包含着ID_Token 和 Access_Token
8,客户端验证ID_Token, 并获得用户的一些身份信息.

Implicit(简化)

不适合于长时间访问。

1
2
3
4
5
6
7
1,客户端准备身份认证请求, 请求里包含所需的参数
2,客户端发送请求到授权服务器
3,授权服务器对最终用户进行身份认证
4,授权服务器获得最终用户的同意/授权
5,授权服务器把最终用户发送回客户端, 同时带着ID_Token.
如果也请求了Access_Token的话, 那么Access_Token也会一同返回.
6,客户端验证ID_Token, 并获得用户的一些身份信息.

Hybrid Flow(混合)

适合于长时间的访问。

要求客户端应用可以安全的维护secret

1
2
3
4
5
6
7
8
9
1,客户端准备身份认证请求, 请求里包含所需的参数
2,客户端发送请求到授权服务器
3,授权服务器对最终用户进行身份认证
4,授权服务器获得最终用户的同意/授权
5,授权服务器把最终用户发送回客户端, 同时带着授权码,
根据响应类型的不同, 也可能还带着一个或者多个其它的参数.
6,客户端使用授权码向Token端点请求一个响应
7,客户端接收到响应, 响应的body里面包含着ID_Token 和 Access_Token
8,客户端验证ID_Token, 并获得用户的一些身份信息.

参考:

OpenID Connect 协议入门指南

Identity Server 4 预备知识 – OpenID Connect 简介

Identity Server 4 预备知识 – OAuth 2.0 简介

[认证授权] 4.OIDC(OpenId Connect)身份认证(核心部分)

RESTful API 设计与实践

协议

API与用户的通信协议,总是使用HTTPs协议。

域名

应该尽量将API部署在专用域名之下。

1
https://api.example.com

如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。

1
https://example.org/api/

版本(Versioning)

应该将API的版本号放入URL。

1
https://api.example.com/v1/

另一种做法是,将版本号放在HTTP头信息中,但不如放入URL方便和直观。

路径(Endpoint)

路径又称”终点”(endpoint),表示API的具体网址。

在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的”集合”(collection),所以API中的名词也应该使用复数。

例如:

1
2
3
https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees

HTTP动词

对于资源的具体操作类型,由HTTP动词表示。

常用的HTTP动词有下面五个(括号里是对应的SQL命令)。

根据 HTTP 规范,动词一律大写。

1
2
3
4
5
GET(SELECT):读取(Read)
POST(CREATE):新建(Create)
PUT(UPDATE):更新(Update)
PATCH(UPDATE):更新(Update),通常是部分更新
DELETE(DELETE):删除(Delete)

还有两个不常用的HTTP动词。

1
2
HEAD:获取资源的元数据。
OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

例子:

1
2
3
4
5
6
7
8
GET /zoos:列出所有动物园
POST /zoos:新建一个动物园
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

URL 设计

动词 + 宾语

RESTful 的核心思想就是,客户端发出的数据操作指令都是”动词 + 宾语”的结构。比如,GET/articles这个命令,GET是动词,/articles是宾语。

动词的覆盖

有些客户端只能使用GETPOST这两种方法。服务器必须接受POST模拟其他三个方法(PUTPATCHDELETE)。

这时,客户端发出的 HTTP 请求,要加上X-HTTP-Method-Override属性,告诉服务器应该使用哪一个动词,覆盖POST方法。

1
2
POST /api/Person/4 HTTP/1.1  
X-HTTP-Method-Override: PUT

X-HTTP-Method-Override指定本次请求的方法是PUT,而不是POST

宾语必须是名词

宾语就是 API 的 URL,是 HTTP 动词作用的对象。它应该是名词,不能是动词。比如,/articles这个 URL 就是正确的。

/getAllCars 是错误的。

复数 URL

建议都使用复数 URL,比如GET/articles/2要好于GET/article/2

避免多级 URL

1
2
3
4
5
// URL 不利于扩展,语义也不明确
GET /authors/12/categories/2

// 更好的写法
GET /authors/12?categories=2

过滤信息(Filtering)

如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。

下面是一些常见的参数:

1
2
3
4
5
?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animalsGET /animals?zoo_id=ID 的含义是相同的。

状态码(Status Codes)

状态码必须精确

客户端的每一次请求,服务器都必须给出回应。回应包括 HTTP 状态码和数据两部分。

HTTP 状态码就是一个三位数,分成五个类别。API 不需要1xx状态码。

1
2
3
4
5
1xx:相关信息
2xx:操作成功
3xx:重定向
4xx:客户端错误
5xx:服务器错误

详细请参考:www.w3.org

2xx 状态码

200状态码表示操作成功,但是不同的方法可以返回更精确的状态码。

1
2
3
4
5
GET: 200 OK
POST: 201 Created
PUT: 200 OK
PATCH: 200 OK
DELETE: 204 No Content

POST返回201状态码,表示生成了新的资源;DELETE返回204状态码,表示资源已经不存在。

202 Accepted状态码表示服务器已经收到请求,但还未进行处理,会在未来再处理,通常用于异步操作。

3xx 状态码

API 用不到301状态码(永久重定向)和302状态码(暂时重定向,307也是这个含义),因为它们可以由应用级别返回,浏览器会直接跳转,API 级别可以不考虑这两种情况。

API 用到的3xx状态码,主要是303 See Other,表示参考另一个 URL。它与302307的含义一样,也是”暂时重定向”,区别在于302307用于GET请求,而303用于POSTPUTDELETE请求。收到303以后,浏览器不会自动跳转,而会让用户自己决定下一步怎么办。下面是一个例子。

1
2
HTTP/1.1 303 See Other
Location: /api/orders/12345

4xx 状态码

4xx状态码表示客户端错误,主要有下面几种。

400 Bad Request:服务器不理解客户端的请求,未做任何处理。

401 Unauthorized:用户未提供身份验证凭据,或者没有通过身份验证。

403 Forbidden:用户通过了身份验证,但是不具有访问资源所需的权限。

404 Not Found:所请求的资源不存在,或不可用。

405 Method Not Allowed:用户已经通过身份验证,但是所用的 HTTP 方法不在他的权限之内。

410 Gone:所请求的资源已从这个地址转移,不再可用。

415 Unsupported Media Type:客户端要求的返回格式不支持。比如,API 只能返回 JSON 格式,但是客户端要求返回 XML 格式。

422 Unprocessable Entity:客户端上传的附件无法处理,导致请求失败。

429 Too Many Requests:客户端的请求次数超过限额。

5xx 状态码

`5xx状态码表示服务端错误。一般来说,API 不会向用户透露服务器的详细信息,所以只要两个状态码就够了。

500 Internal Server Error:客户端请求有效,服务器处理时发生了意外。

503 Service Unavailable:服务器无法处理请求,一般用于网站维护状态。

服务器回应

不要返回纯本文

API 返回的数据格式,不应该是纯文本,而应该是一个 JSON 对象,因为这样才能返回标准的结构化数据。所以,服务器回应的 HTTP 头的Content-Type属性要设为application/json

客户端请求时,也要明确告诉服务器,可以接受 JSON 格式,即请求的 HTTP 头的ACCEPT属性也要设成application/json

1
2
GET /orders/2 HTTP/1.1 
Accept: application/json

错误处理(Error handling)

发生错误时,不要返回 200 状态码,状态码反映发生的错误,具体的错误信息放在数据体里面返回。

1
2
3
4
5
6
7
8
9
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"error": "Invalid payoad.",
"detail": {
"surname": "This field is required."
}
}

返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。

1
2
3
4
5
6
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档

Hypermedia API

RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法。

Hypermedia API的设计被称为HATEOAS。

例子:

1
2
3
4
5
6
{"link": {
"rel": "collection https://www.example.com/zoos",
"href": "https://api.example.com/zoos",
"title": "List of zoos",
"type": "application/vnd.yourformat+json"
}}

参考:

RESTful API 最佳实践

RESTful API 设计指南

RESTful架构学习笔记

REST架构原则: Representational State Transfer的缩写。翻译是”表现层状态转化”。
全称:Resources Representational State Transfer,即资源表现层状态转化。

如果一个架构符合REST原则,就称它为RESTful架构。

资源(Resources)

所谓”资源”,就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。

表现层(Representation)

“资源”是一种信息实体,它可以有多种外在表现形式。我们把”资源”具体呈现出来的形式,叫做它的”表现层”(Representation)。

状态转化(State Transfer)

访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生”状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是”表现层状态转化”。

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

RESTful架构

(1)每一个URI代表一种资源;

(2)客户端和服务器之间,传递这种资源的某种表现层;

(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”。

参考:

理解RESTful架构

OAuth 2.0学习笔记

OAuth的作用就是让”客户端”安全可控地获取”用户”的授权,与”服务商提供商”进行互动。

OAuth在”客户端”与”服务提供商”之间,设置了一个授权层(authorization layer)。”客户端”不能直接登录”服务提供商”,只能登录授权层,以此将用户与客户端区分开来。”客户端”登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。

“客户端”登录授权层以后,”服务提供商”根据令牌的权限范围和有效期,向”客户端”开放用户储存的资料。

Authentication: 证明;鉴定
Authorization: 授权,认可;批准,委任

名词定义

client 或 Third-party application :第三方应用程序,又称”客户端”(client)。

HTTP service:HTTP服务提供商,简称”服务提供商”。

Resource Owner:资源所有者,又称”用户”(user)。

User Agent:用户代理,本文中就是指浏览器。

Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。

Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。

运行流程

bg2014051203.png

1
2
3
4
5
6
7
8
9
10
11
(A)用户打开客户端以后,客户端要求用户给予授权。

(B)用户同意给予客户端授权。

(C)客户端使用上一步获得的授权,向认证服务器申请令牌。

(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。

(E)客户端使用令牌,向资源服务器申请获取资源。

(F)资源服务器确认令牌无误,同意向客户端开放资源。

其中,B阶段,对客户端授权是关键。有了这个授权以后,客户端就可以获取令牌,进而凭令牌获取资源。

获取授权的四种模式

客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

授权码模式(authorization code)

授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与”服务提供商”的认证服务器进行互动。例如,微信登录。

注:相关参数使用JSON格式发送(Content-Type: application/json)。此外,HTTP头信息中明确指定不得缓存。

bg2014051204.png

具体步骤:

1
2
3
4
5
6
7
8
9
10
11
12
(A)用户访问客户端,后者将前者导向认证服务器。

(B)用户选择是否给予客户端授权。

(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),
同时附上一个授权码。

(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台
的服务器上完成的,对用户不可见。

(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)
和更新令牌(refresh token)。

A步骤中,客户端申请认证的URI,包含以下参数:

  • response_type:表示授权类型,必选项,此处的值固定为”code”
  • client_id:表示客户端的ID,必选项
  • redirect_uri:表示重定向URI,可选项
  • scope:表示申请的权限范围,可选项
  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

例子:

1
2
3
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com

B步骤中,用户动作选择是否给客户端授权,例如微信扫码之后确认登录动作等。

C步骤中,服务器回应客户端的URI,包含以下参数:

  • code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

例子:

1
2
3
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz

D步骤中,客户端向认证服务器申请令牌的HTTP请求,包含以下参数:

  • grant_type:表示使用的授权模式,必选项,此处的值固定为”authorization_code”。
  • code:表示上一步获得的授权码,必选项。
  • redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
  • client_id:表示客户端ID,必选项。

例子:

1
2
3
4
5
6
7
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

E步骤中,认证服务器发送的HTTP回复,包含以下参数:

  • access_token:表示访问令牌,必选项。
  • token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
  • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
  • refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}

简化模式

简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了”授权码”这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。

bg2014051205.png

运行流程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(A)客户端将用户导向认证服务器。

(B)用户决定是否给于客户端授权。

(C)假设用户给予授权,认证服务器将用户导向客户端指定的"重定向URI",
并在URI的Hash部分包含了访问令牌。

(D)浏览器向资源服务器发出请求,其中不包括上一步收到的Hash值。

(E)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。

(F)浏览器执行上一步获得的脚本,提取出令牌。

(G)浏览器将令牌发给客户端。

A步骤中,客户端发出的HTTP请求,包含以下参数:

  • response_type:表示授权类型,此处的值固定为”token”,必选项。
  • client_id:表示客户端的ID,必选项。
  • redirect_uri:表示重定向的URI,可选项。
  • scope:表示权限范围,可选项。
  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

例子:

1
2
3
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com

C步骤中,认证服务器回应客户端的URI,包含以下参数:

  • access_token:表示访问令牌,必选项。
  • token_type:表示令牌类型,该值大小写不敏感,必选项。
  • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

例子:

1
2
3
HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
&state=xyz&token_type=example&expires_in=3600

在上面的例子中,认证服务器用HTTP头信息的Location栏,指定浏览器重定向的网址。注意,在这个网址的Hash部分包含了令牌。

根据上面的D步骤,下一步浏览器会访问Location指定的网址,但是Hash部分不会发送。接下来的E步骤,服务提供商的资源服务器发送过来的代码,会提取出Hash中的令牌。

密码模式

密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向”服务商提供商”索要授权。

在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。

bg2014051206.png

具体步骤:

1
2
3
4
5
(A)用户向客户端提供用户名和密码。

(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。

(C)认证服务器确认无误后,向客户端提供访问令牌。

B步骤中,客户端发出的HTTP请求,包含以下参数:

  • grant_type:表示授权类型,此处的值固定为”password”,必选项。
  • username:表示用户名,必选项。
  • password:表示用户的密码,必选项。
  • scope:表示权限范围,可选项。

例子:

1
2
3
4
5
6
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=johndoe&password=A3ddj3w

C步骤中,认证服务器向客户端发送访问令牌。如下:

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}

整个过程中,客户端不得保存用户的密码。

客户端模式

客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向”服务提供商”进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求”服务提供商”提供服务,其实不存在授权问题。

bg2014051207.png

具体步骤:

1
2
3
(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。

(B)认证服务器确认无误后,向客户端提供访问令牌。

A步骤中,客户端发出的HTTP请求,包含以下参数:

granttype:表示授权类型,此处的值固定为”clientcredentials”,必选项。
scope:表示权限范围,可选项。

1
2
3
4
5
6
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

认证服务器必须以某种方式,验证客户端身份。

B步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。

1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}

更新令牌

如果用户访问的时候,客户端的”访问令牌”已经过期,则需要使用”更新令牌”申请一个新的访问令牌。

客户端发出更新令牌的HTTP请求,包含以下参数:

  • granttype:表示使用的授权模式,此处的值固定为”refreshtoken”,必选项。
  • refresh_token:表示早前收到的更新令牌,必选项。
  • scope:表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致。
1
2
3
4
5
6
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

参考:

理解OAuth 2.0

IdentityServer4 实现 OpenID Connect 和 OAuth 2.0

Sql-Server基础之Grouping用法

GROUPING 是一个聚合函数,用在含有 CUBEROLLUP 语句的SQL语句中,当结果集中的数据行是由 CUBEROLLUP 运算产生的(添加的)则该函数返回1,否则返回0。

语法: GROUPING(column_name)

其中 column_name 是用在 CUBEROLLUP 运算的列 或 group by 后的列。

注意:

  • (1)只有使用了 CUBEROLLUP 运算符的SQL中才能使用 GROUPING
  • (2)GROUPING 后面的列 名可以是 CUBEROLLUP 运算符中使用的列名,也可以是 group by 中的列名

CUBE 生成的结果集显示了所选列中值的所有组合的聚合。
ROLLUP 生成的结果集显示了所选列中值的某一层次结构的聚合。

** CUBE**

CUBE 生成的结果集显示了所选列中值的所有组合的聚合。

1
2
SELECT CourseID,StudentID,SUM(Score) FROM [dbo].[Score] 
GROUP BY CourseID,StudentID WITH CUBE

结果:
QQ截图20190316155035.png

** ROLLUP**

1
2
SELECT StudentID,CourseID,SUM(Score)  FROM [dbo].[Score] 
GROUP BY StudentID,CourseID WITH ROLLUP

结果:
QQ截图20190316160822.png

** GROUPING**

获取每个学生成绩的总和。以下示例结果相同

1
2
SELECT StudentID,CourseID,SUM(Score),grouping(CourseID) FROM [dbo].[Score] 
GROUP BY StudentID,CourseID WITH CUBE HAVING grouping(CourseID)=1

结果:
QQ截图20190316161849.png

1
2
SELECT StudentID,CourseID,SUM(Score),grouping(CourseID)  FROM [dbo].[Score] 
GROUP BY StudentID,CourseID WITH ROLLUP HAVING grouping(CourseID)=1

结果:
QQ截图20190316162226.png

参考:

Sql学习第四天——SQL 关于with cube ,with rollup 和 grouping

GROUPING 用法