
OWIN 是一个开源开放的标准, 有助于建设 .NET 开发的开源生态环境,OWIN 定义了如下几个概念:
服务器 (Server)
HTTP 服务器直接与客户端交互, 并用 OWIN 语义处理请求,服务器需要一个适配层将客户请求转换 成 OWIN 语义。 支持 OWIN 的服务器有 Katana 和 Nowin 。
Web 框架 (Web Framework)
构建在 OWIN 之上的自包含的独立组件, 向 Web 应用提供可用的对象模型或者接口。 Web 框架可 能需要一个适配层来转换 OWIN 语义。 支持 OWIN 的 Web 框架有:
Nancy
SignalR
WebApi
FubuMVC
Simple.Web
DuoVia.Http
Web 应用 (Web Application)
一个特定的 Web 应用, 通常构建在 Web 框架之上, 使用 OWIN 兼容的服务器运行。
中间件 (Middleware)
特定目的的服务器和应用之间的可插拔组件, 可以监视、 路由、 修改请求与响应。
宿主 (Host)
应用与服务器所在的进程, 主要负责应用的启动, 有些服务器自身也是宿主, 比如 Nowin 。
为什么使用 OWIN
正如上面所说, OWIN 定义了 .NET Web 服务器与 .NET Web 应用之间的标准接口, 将应用与服务器 解耦, 使得便携式 .NET Web 应用以及跨平台的愿望成为现实, 标准的 OWIN 应用可以在任何 OWIN 兼容的服务器上运行, 不再依赖与 Windows 和 IIS 。
怎么使用 OWIN
OWIN 通过 NuGet 包的形式发布, 获取和使用都非常方便。 下面就先建立一个最简单的 OWIN 应用:
打开 Xamarin Studio, 新建一个 C# 命令行程序, 如下图所示:
OWIN Hello
然后打开项目属性, 确认目标框架设置为 Mono/.NET 4.5 , 如下图所示:
向项目中添加如下几个 NuGet 包:
Owin
Microsoft.Owin
Microsoft.Owin.Hosting
Microsoft.Owin.Host.HttpListener
添加一个 OWIN Startup 类, 代码如下:
public class Startup {
public void Configuration(IAppBuilder appBuilder) {
appBuilder.Run(HandleRequest)
}
static Task HandleRequest(IOwinContext context) {
context.Response.ContentType = "text/plain"
return context.Response.WriteAsync("Hello, world!")
}
}
OWIN 约定的处理请求的代理类型是:
Func<IOWinContext, Task>handler
对应上面 Startup 类的 HandleRequest 方法, 所以上面的 Startup 类就定义了一个最简单的 OWIN 应用, 向客户端输出 Hello, World!
在自动生成的 Program.cs 文件中的 Main 方法中添加如下代码, 来启动 OWIN 应用:
class MainClass {
public static void Main(string[] args) {
var url = "http://localhost:8080/"
var startOpts = new StartOptions(url) {
}
using (WebApp.Start<Startup>(startOpts)) {
Console.WriteLine("Server run at " + url + " , press Enter to exit.")
Console.ReadLine()
}
}
}
现在开始运行程序, 命令行显示如下:
打开浏览器, 访问 http://localhost:8080/ , 得到的响应如下:
OWIN Hello
到目前为止, 没有 Windows , 更没有 IIS , OWIN 应用就能正常运行了。
我不知道有几种,但是我觉得用Microsoft.Owin.Security.OAuth中间件可能是最容易想到的办法。不过OWIN协议真的很无语,一方面正在走向顶点,一方面居然有要被弃用的感觉…….net core里已经完全看不到它的踪影了
用户服务的例子,请看 这里
IdentityServer3 定义了一个 IUserService 接口来抽象下层的用户身份管理系统,它为本地和第三方账号的用户验证语义,它也提供了IdentityServer生成令牌需要的身份和声明以及用户信息endpoint.用户服务更提供了登陆的工作流(比如接受用户许可协议或者登陆额外需要的2fa)
用户服务的方法分为认证相关方法和令牌声明信息和用户信息相关方法。
IUserService 定义了下面的方法:
所有的认证方法都会收到 SignInMessage 上下文信息:
所有的认证方法都会返回 AuthenticateResult ,它有很多可能的输出结果。它有多个构造函数来初始化不同的输出:
完整登陆必须提供用户的 subject 和 name , subject 是用户服务使用的用户唯一标识, name 用来显示在用户界面上。
声明(Claim) 也可能提供,用户服务的有些方法可能需要这些附加的信息。
如果是通过第三方登陆,那么 identityProvider 参数也需要提供。这个参数可以通过身份令牌里的 idp 声明提供或者用户信息endpoint. 如果通过本地账号登陆,这个参数不应该被使用(会使用默认的 Constants.BuiltInIdentityProvider ).
可选参数 authenticationMethod 生成 amr 声明,用来说明用户该如何验证,如:双因子验证还是客户端证书验证。如果没有传入,那么本地账号期望使用 password ,如果是第三方登陆,那么这个值会是 external 表示是第三方登陆。
所有这些声明( subject , name , idp , amr 和其他 Claim 列表)会用来生成认证cookie。这个认证cookie会由katana cookie认证中间件来管理。认证中间件会使用常量 Constants.PrimaryAuthenticationType 来设定 AuthenticationType 值。
ClaimsPrincipal 由完整登陆创建, IUserService 其它API会通过 Subject 使用。( PostAuthenticateAsync , GetProfileDataAsync , IsActiveAsync , and SignOutAsync ).
除了完整登陆,认证API还可以执行"部分登陆".部分登陆允许用户服务中断用户的正常登陆过程,让用户到一个自定义的页面去完成一些任务后才能继续登陆。(比如完成注册,接受用户许可协议,执行2fa)。、
部分登陆会通过katana认证中间件发送一个"部分登陆的"cookie,认证中间件会使用常量 Constants.PrimaryAuthenticationType 来设定 AuthenticationType 值。
部分登陆可以创建和完整登陆一样的参数( subject , name , claims , amr , and idp )以及 redirectPath . 部分登陆也可以只创建 claims 集合和 redirectPath . 两种方法的最大区别是用户身份已经确认。
托管程序会提供 redirectPath ,用来重定向到自定义的网页上,在这个网页上用户声明可以用来完成自定义的工作流。这个页面可以通过 GetIdentityServerPartialLoginAsync OWIN environment extension method 来获取声明信息.
当用户完成了自定义的任务(接受用户许可协议,注册或者2fa), 用户会被重定向会登陆页面完成完整的登陆过程。重定向用户回来的URL可以通过 GetPartialLoginResumeUrlAsync OWIN environment extension method 方法得到.如果需要用户重新登陆,则调用 GetPartialLoginRestartUrlAsync OWIN environment extension method .
在重定向回登陆页面前,在部分登陆的声明可以通过 UpdatePartialLoginClaimsAsync OWIN environment extension method 改变.如果需要移除或者清除部分登陆则可以使用 RemovePartialLoginCookie OWIN environment extension method .
如果用户从第三方登陆并且没有对应的本地账号。自定义的用户服务也可以重定向会客户端,这需要通过创建一个带有 ExternalIdentity 的 AuthenticateResult ,并传给 AuthenticateExternalAsync API。这会创建一个部分登陆(和上面一样t通过 PartialSignInAuthenticationType ),但是cookie里会用 external_provider_user_id 代替subject声明(或者通过 Constants.ClaimTypes.ExternalProviderUserId ),声明里的Issuer是第三方标识,这个标识可以用来创建本地账号并和第三方账号关联。
一旦用户完成了本地账号注册,他会被重定向会登陆页面来完成完整登陆(和上面机制一样).
最后,认证API可以提供错误信息显示在登陆页面上,这可以通过使用 AuthenticateResult 的接受字符串(错误信息)构造函数来实现。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)