我有一个由OWIN托管的Nancy项目。目前它有自己的用户身份验证。计划是改变它,使我的项目与外部认证模型兼容 - 即基于SAML;我有一个本地身份提供商,并设法处理我的服务和IdP之间的通信。我通过使用Kentor.AuthServices库(https://github.com/KentorIT/authservices)
实现了这一目标let CreateSPOptions() : SPOptions =
let spOptions = new SPOptions()
spOptions.EntityId <- new EntityId("<my_service_ID>")
spOptions.ReturnUrl <- new Uri("http://localhost:5012/login")
spOptions.MinIncomingSigningAlgorithm <- "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
spOptions
let ConfigureAuthOptions() : KentorAuthServicesAuthenticationOptions =
let spOptions = CreateSPOptions()
let authServicesOptions = new KentorAuthServicesAuthenticationOptions(false)
authServicesOptions.SPOptions <- spOptions
let idp = new IdentityProvider(new EntityId("<my_IdP_ID>"), spOptions)
idp.AllowUnsolicitedAuthnResponse <- true
idp.Binding <- Saml2BindingType.HttpRedirect
idp.MetadataLocation <- @"Metadata\provider.xml"
authServicesOptions.IdentityProviders.Add(idp);
authServicesOptions
let Configure (app : IAppBuilder) =
let cookieOptions = new CookieAuthenticationOptions()
cookieOptions.LoginPath <- new PathString("/Login")
cookieOptions.LogoutPath <- new PathString("/Logout")
cookieOptions.AuthenticationType <- "KentorAuthServices"
cookieOptions.AuthenticationMode <- AuthenticationMode.Active
cookieOptions.Provider <- new CookieAuthenticationProvider()
app.UseCookieAuthentication(cookieOptions) |> ignore
app.SetDefaultSignInAsAuthenticationType("KentorAuthServices")
app.UseKentorAuthServicesAuthentication(ConfigureAuthOptions()) |> ignore
app
但是,因此用户信息现在存储在Owin上下文中,因此我不能依赖this.Context.CurrentUser
(其中this
指的是当前的Nancy模块),我可以&# 39;使用以下方法保护我的模块:
type SecuredModule() as this =
inherit NancyModule()
do
this.RequiresAuthentication()
this.Get.["/"] <- ....
我知道Nancy.MSOwinSecurity
包中提供的功能允许我引用OwinContext,例如。
type SecuredModule() as this =
inherit NancyModule()
do
this.RequiresMSOwinAuthentication()
this.Get.["/"] <- ...
但问题是,有许多与项目相关的测试假设用户信息存储在Nancy上下文中。绝大多数测试都基于模拟对象:
let createBrowser rootFolder =
let docStore = DocumentStore(rootFolder)
let config (w:ConfigurableBootstrapper.ConfigurableBootstrapperConfigurator) =
w.Module(new UnsecuredModule(docStore))
.Module(new SecuredModule(docStore))
.RequestStartup(fun _ _ (context: NancyContext) ->
context.CurrentUser <- new UserIdentity("MyServiceUnitTests", Seq.empty))
|> ignore
在处理来自我的IdP的响应并手动覆盖context.CurrentUser时,我尝试了相同的操作,但重定向后信息丢失了:
type LoginModule(userDatabase: UserDatabase) as this =
inherit NancyModule()
do
this.Get.["/login"] <-
fun _ ->
match this.Context.GetMSOwinUser() with
| null ->
let authenticationManager = this.Context.GetAuthenticationManager();
let properties = new AuthenticationProperties()
properties.RedirectUri <- "/Web.Documents/login"
authenticationManager.Challenge(properties, "KentorAuthServices")
HttpStatusCode.Unauthorized |> box
| user ->
let userName = user.Identity.Name
let ipAddress = this.Context.Request.UserHostAddress
Log.Info "{@user} {@ipaddress} logged in" [
"user" => userName
"ipaddress" => ipAddress
]
this.Context.CurrentUser <- new UserIdentity("MyServiceUnitTests", Seq.empty)
this.Context.GetRedirect("~/") |> box
显然,我不想对我的服务进行太多更改。理想情况下,我希望以某种方式将用户信息移动到Nancy Context - 然后我很乐意去,因为我也不需要调整~50个测试。什么是最好的解决方案?