一、前言
想必大家或多或少都聽過微軟推出的ASP.NET Identity技術,可以簡單的認為就是一種授權的實現
很巧的是,Nancy中也有與之相類似的技術Authentication,這兩者之間都用到了一些相通的安全技術
(我沒有去看ASP.NET Identity的內部實現,是從它的簡單用法中判斷的)
正式開始介紹之前先推薦幾篇ASP.NET Identity的好文章
r01cn 的 ASP.NET Identity系列教程(目錄)
騰飛(Jesse) 的 MVC5 - ASP.NET Identity登錄原理 - Claims-based認證和OWIN
好了,下面還是用demo的形式來介紹怎么簡單使用Forms authentication吧
二、簡單使用
1)、新建一個空的asp.net項目
2)、通過NuGet安裝相應的包
1 Install-Package Nancy 2 Install-Package Nancy.Hosting.Aspnet 3 Install-Package Nancy.Authentication.Forms 4 Install-Package Dapper
由於用到了數據庫訪問,所以還安裝了Dapper
3)、建立數據表
1 CREATE TABLE [dbo].[SystemUser]( 2 [SystemUserId] [uniqueidentifier] NOT NULL, 3 [SystemUserName] [nvarchar](50) NOT NULL, 4 [SystemUserPassword] [nvarchar](50) NOT NULL, 5 CONSTRAINT [PK_SystemUser] PRIMARY KEY CLUSTERED 6 ( 7 [SystemUserId] ASC 8 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 9 ) ON [PRIMARY] 10 GO
同時像表中插入兩條數據
1 INSERT INTO [dbo].[SystemUser]([SystemUserId],[SystemUserName],[SystemUserPassword]) 2 VALUES(newid(),'catcher','123') 3 INSERT INTO [dbo].[SystemUser]([SystemUserId],[SystemUserName],[SystemUserPassword]) 4 VALUES(newid(),'admin','123')
注:由於是演示,所以密碼沒有進行加密處理
4)、建立相應的文件夾

Models用於存放模型
Modules用於存放相應的操作
Views用於存放視圖
5)、編寫模型 SystemUser.cs
1 public class SystemUser 2 { 3 public Guid SystemUserId { get; set; } 4 public string SystemUserName { get; set; } 5 public string SystemUserPassword { get; set; } 6 }
6)、編寫HomeModule.cs
1 using Dapper; 2 using Nancy; 3 using Nancy.Authentication.Forms; 4 using Nancy.ModelBinding; 5 using NancyDemoForFormsauthentication.Models; 6 using System.Data; 7 using System.Data.SqlClient; 8 using System.Linq; 9 namespace NancyDemoForFormsauthentication.Modules 10 { 11 public class HomeModule : NancyModule 12 { 13 public HomeModule() 14 { 15 Get["/"] = _ => 16 { 17 return View["index"]; 18 }; 19 Get["/login"] = _ => 20 { 21 return View["login"]; 22 }; 23 Post["/login"] = _ => 24 { 25 var loginUser = this.Bind<SystemUser>(); 26 SystemUser user = GetValidUser(loginUser.SystemUserName, loginUser.SystemUserPassword); 27 if (user == null) 28 { 29 return Response.AsText("出錯了", "text/html;charset=UTF-8"); 30 } 31 return this.LoginAndRedirect(user.SystemUserId, fallbackRedirectUrl: "/secure"); 32 }; 33 } 34 private readonly string sqlconnection = 35 "Data Source=127.0.0.1;Initial Catalog=NancyDemo;User Id=sa;Password=dream_time1314;"; 36 private SqlConnection OpenConnection() 37 { 38 SqlConnection connection = new SqlConnection(sqlconnection); 39 connection.Open(); 40 return connection; 41 } 42 private SystemUser GetValidUser(string name, string pwd) 43 { 44 using (IDbConnection conn = OpenConnection()) 45 { 46 const string query = "select * from SystemUser where SystemUserName=@SystemUserName and SystemUserPassword=@SystemUserPassword"; 47 return conn.Query<SystemUser>(query, new { SystemUserName = name, SystemUserPassword = pwd }).SingleOrDefault(); 48 } 49 } 50 } 51 }
其中,登錄的post方法中用到了 LoginAndRedirect 這個靜態方法
這個方法位於ModuleExtensions.cs中,返回值是Response類型的
1 public static Response LoginAndRedirect(this INancyModule module, Guid userIdentifier, DateTime? cookieExpiry = null, string fallbackRedirectUrl = "/") 2 { 3 return FormsAuthentication.UserLoggedInRedirectResponse(module.Context, userIdentifier, cookieExpiry, fallbackRedirectUrl); 4 }
看方法名都能知道這個是用來干什么的!
還有Response.AsText后面的第二個參數可以讓中文不亂碼!!
7)、編寫相應的視圖
index.html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title></title> 5 <meta charset="utf-8" /> 6 </head> 7 <body> 8 <h2>Nancy之基於Forms authentication的簡單使用</h2> 9 <p>訪問需要權限的頁面</p> 10 <a href="/secure">secure</a> 11 </body> 12 </html>
login.html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title></title> 5 <meta charset="utf-8" /> 6 </head> 7 <body> 8 <form method="post" action="/login"> 9 <label>姓名:</label><input type="text" name="SystemUserName" /><br /> 10 <label>密碼:</label><input type="password" name="SystemUserPassword" /><br /> 11 <input type="submit" /> 12 </form> 13 </body> 14 </html>
8)、編寫SecureModule.cs
1 using Nancy; 2 using Nancy.Security; 3 4 namespace NancyDemoForFormsauthentication.Modules 5 { 6 public class SecureModule : NancyModule 7 { 8 public SecureModule() 9 { 10 this.RequiresAuthentication(); 11 Get["/secure"] = _ => 12 { 13 return "Hello ," + this.Context.CurrentUser.UserName; 14 }; 15 } 16 } 17 }
其中
1 this.RequiresAuthentication();
這句是關鍵!!表明需要驗證才能通過。位於Nancy.Security這個命名空間
通過驗證訪問后會打印出當前的用戶名稱。
9)、編寫Bootstraper.cs
1 using Nancy; 2 using Nancy.Authentication.Forms; 3 using Nancy.TinyIoc; 4 using Nancy.Bootstrapper; 5 namespace NancyDemoForFormsauthentication 6 { 7 public class Bootstrapper : DefaultNancyBootstrapper 8 { 9 protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context) 10 { 11 base.ConfigureRequestContainer(container, context); 12 container.Register<IUserMapper, UserMapper>(); 13 } 14 protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context) 15 { 16 base.RequestStartup(container, pipelines, context); 17 var formsAuthConfiguration = new FormsAuthenticationConfiguration 18 { 19 RedirectUrl = "~/login", 20 UserMapper = container.Resolve<IUserMapper>(), 21 }; 22 FormsAuthentication.Enable(pipelines, formsAuthConfiguration); 23 } 24 } 25 }
這里是至關重要的一步!!!
要在RequestStartup中啟用我們的FormsAuthentication!!
同時我們還要配置FormsAuthenticationConfiguration
注冊了UserMapper,所以我們接下來就是實現UserMapper
10)、編寫UserMapper.cs
1 using Dapper; 2 using Nancy; 3 using Nancy.Authentication.Forms; 4 using Nancy.Security; 5 using NancyDemoForFormsauthentication.Models; 6 using System; 7 using System.Data; 8 using System.Data.SqlClient; 9 using System.Linq; 10 namespace NancyDemoForFormsauthentication 11 { 12 public class UserMapper : IUserMapper 13 { 14 public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context) 15 { 16 using (IDbConnection conn = OpenConnection()) 17 { 18 const string query = "select * from SystemUser where SystemUserId=@SystemUserId"; 19 var user = conn.Query<SystemUser>(query, new { SystemUserId = identifier }).SingleOrDefault(); 20 if (user == null) 21 { 22 return null; 23 } 24 else 25 { 26 return new UserIdentity 27 { 28 UserName = user.SystemUserName, 29 Claims = new[] { "SystemUser"} 30 }; 31 } 32 } 33 } 34 private readonly string sqlconnection = 35 "Data Source=127.0.0.1;Initial Catalog=NancyDemo;User Id=sa;Password=dream_time1314;"; 36 private SqlConnection OpenConnection() 37 { 38 SqlConnection connection = new SqlConnection(sqlconnection); 39 connection.Open(); 40 return connection; 41 } 42 } 43 }
UserMapper必須要實現IUserMapper這個接口!同時返回一個實現IUserIdentity接口的對象。
11)、編寫UserIdentity.cs
1 using Nancy.Security; 2 using System.Collections.Generic; 3 namespace NancyDemoForFormsauthentication 4 { 5 public class UserIdentity : IUserIdentity 6 { 7 public string UserName { get; set; } 8 public IEnumerable<string> Claims { get; set; } 9 } 10 }
到這里所有的工作都已經做完了,下面就是看看效果了

我們點擊 secure鏈接,發現自動跳轉到登錄界面了!!

我們輸入用戶名和密碼

登錄成功,並返回到secure頁面了!

當我們輸入錯誤的用戶名和密碼時

最后是本次示例代碼:
https://github.com/hwqdt/Demos/tree/master/src/NancyDemoForFormsauthentication
