Nancy 也有提供驗證讓我們保護資源,接下來看看如何實作
Nancy 驗證
要訪問當前經過身份驗證的用戶,只需訪問 NancyContext.CurrentUser 屬性。 值若為 null 表示當前請求的用戶尚未通過身份驗證,其他任何內容均表示該用戶已通過身份驗證。
是否通過驗證
判斷 NancyContext.CurrentUser 是否為 null,以下範例是使用 Before Pipeline
public class SecureModule : NancyModule
{
public SecureModule()
{
Before += ctx => {
return (this.Context.CurrentUser == null) ? new HtmlResponse(HttpStatusCode.Unauthorized) : null;
};
// Your routes here
}
}
UserIdentity.UserName 是否為空,要自行實作這個抽象
public interface IUserIdentity
{
/// <summary>
/// Gets or sets the name of the current user.
/// </summary>
string UserName { get; set; }
/// <summary>
/// Gets or set the claims of the current user.
/// </summary>
IEnumerable<string> Claims { get; set; }
}
為了避免重複建造輪子,Nancy 提供了以下擴充方法
RequiresAuthentication
:確保已通過身分驗證,若沒通過將回傳 HttpStatusCode.Unauthorized
,驗證方式,CurrentUser
不為 null,UserName
不為空;範例如下:
public class SecureModule : NancyModule
{
public SecureModule()
{
this.RequiresAuthentication();
}
// Your routes here
}
RequiresClaims
:啟用後,必須滿足所有的 Claim 定義
RequiresAnyClaim
:只要有滿足 Claim 定義中的其中一個
RequiresValidatedClaims
:定義一個方法讓你完整的控制 Claims laims 驗證流程,方法簽章為 Func<IEnumerable<string>, bool>
RequiresHttps
:必須要是 Https
範例如下:
public class SecureModule : NancyModule
{
public SecureModule()
{
this.RequiresHttps();
this.RequiresAuthentication();
this.RequiresClaims(new [] { "Admin" });
}
// Your routes here
}
或是你可以定義自己的擴充方法,範例如下:
public static class ModuleSecurity
{
public static void RequiresAuthentication(this NancyModule module)
{
module.Before.AddItemToEndOfPipeline(RequiresAuthentication);
}
private static Response RequiresAuthentication(NancyContext context)
{
Response response = null;
if ((context.CurrentUser == null) ||
String.IsNullOrWhiteSpace(context.CurrentUser.UserName))
{
response = new Response { StatusCode = HttpStatusCode.Unauthorized };
}
return response;
}
}
Basic Authentication
開發環境
-
VS 2019
-
.NET Framework 4
-
Nancy 1.4.1
安裝套件
Install-Package Nancy.Authentication.Basic -Version 1.4.1
Install-Package Nancy.Hosting.Self -Version 1.4.1
實作 IUserIdentity
public class UserIdentity : IUserIdentity
{
public string UserName { get; set; }
public IEnumerable<string> Claims { get; set; }
}
實作 IUserValidator
在這裡驗證帳號、密碼,為了演示沒有寫得很完整,你得自己實作完整的驗證
public class UserValidator : IUserValidator
{
public IUserIdentity Validate(string username, string password)
{
if (username == "yao" && password == "pass@w0rd1~")
{
var identity = new UserIdentity
{
UserName = username,
Claims = new List<string> {"User"}
};
return identity;
}
//anonymous.
return null;
}
}
定義 NancyModule
調用 RequiresAuthentication 方法
public class GeneratorNancyModule : NancyModule
{
public GeneratorNancyModule()
{
this.RequiresAuthentication();
this.Get["guid"] = p => Guid.NewGuid().ToString();
this.Get["id"] = p => Guid.NewGuid().ToString();
}
}
啟用 Basic Authentication
這裡我使用 Bootstrapper 的 ApplicationStartup 啟用 Basic Authentication
public class AuthenticationBootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
var configuration = new BasicAuthenticationConfiguration(container.Resolve<IUserValidator>(),
"MyRealm",
UserPromptBehaviour.NonAjax);
pipelines.EnableBasicAuthentication(configuration);
}
}
Ctrl+F5 執行應用程式,若有 URL 保留區的問題請參考以下連結
https://dotblogs.com.tw/yc421206/2020/01/30/via_nancy_create_rest_api#%E7%B6%81%E5%AE%9A%20URL
用瀏覽器訪問服務,就能看到驗證視窗跳出來了
輸入帳密,就能訪問資源,得到資料
接著換用 Postman 調試,當沒有帶著 Authentication Header 訪問資源時會得到 401
驗證完成後順利的得到資料
允許匿名訪問
在 ASP.NET MVC、Web API,有 [Authorize]、[AllowAnonymous] 可以讓我們決定哪些資源需要授權才能訪問,在 Nancy 要怎麼實現?
我實作一個擴充方法,排除需要驗證的 Route Name
public static class ModuleSecurityExtension
{
public static void RequiresAuthentication(this INancyModule module, string[] excludes)
{
module.AddBeforeHookOrExecute(p =>
{
Response response = null;
if (excludes.Contains(p.ResolvedRoute.Description.Name))
{
return response;
}
if (p.CurrentUser == null ||
string.IsNullOrWhiteSpace(p.CurrentUser.UserName))
{
response = new Response
{
StatusCode = HttpStatusCode.Unauthorized
};
}
return response;
}, "Requires Authentication");
}
}
在 NancyModule 調用 RequiresAuthentication 方法並傳入不需要驗證的 Route Name
public class GeneratorNancyModule : NancyModule
{
public GeneratorNancyModule()
{
//this.RequiresAuthentication();
this.RequiresAuthentication(new[] {"name:id"});
this.Get["name:guid","guid"] = p => Guid.NewGuid().ToString();
this.Get["name:id","id"] = p => Guid.NewGuid().ToString();
}
}
範例位置
https://github.com/yaochangyu/sample.dotblog/tree/master/Nancy/Lab.Security
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET