題外話: 接上篇吧。上篇主要是介紹下LayUI的使用,太興奮手打代碼去了- -。 其實這個項目用了Unity這個IOC框架,畢竟人要有夢想。感興趣的可以自己去瞭解下,後面有機會會說說對於IOC和DI的個人拙見以及Unity的使用。 進入正題。 二.WebApi 一個有夢想的鹹魚做的一個有夢想的dem ...
題外話:
接上篇吧。上篇主要是介紹下LayUI的使用,太興奮手打代碼去了- -。
其實這個項目用了Unity這個IOC框架,畢竟人要有夢想。感興趣的可以自己去瞭解下,後面有機會會說說對於IOC和DI的個人拙見以及Unity的使用。
進入正題。
二.WebApi
一個有夢想的鹹魚做的一個有夢想的demo項目就需要有夢想的考慮後期維護與擴展,那麼就需要從建項目開始做好文件分類。
打開VS,選擇ASP .NET Web應用程式(.NET Framework)創建一個新的項目命名Demo,然後選擇Web Api,然後建立項目。註意看項目下有個Area的文件夾,作用呢其實就是可以區分控制器,方便管理,而且控制器名稱可以重名。
畢竟是個B/S項目,後臺所接收的請求都屬於http請求,要處理這些請求後臺,就會涉及到安全問題,也就是許可權問題,畢竟要有夢想,還是可以發佈上伺服器的。而這個安全問題並不是只用用戶登錄驗證就能解決的,這時候就會涉及到許可權問題,參考淘寶,你可以隨意瀏覽,但是一些額外操作則需要登錄。
所以這裡我是考慮FormsAuthenticationTicket身份驗證配合授權屬性AuthorizeAttribute。
Ticket,顧名思義,想入場看比賽是需要門票的,那麼想進入自己的網站或者有資料庫操作時,我們可以為用戶設置門票。
進而小朋友些許問號,演唱會門票還有前排後排區別,考慮到實際應用情況,我們是否也需要對於用戶進行許可權區分,這樣比較符合實際情況?這樣是否更靈活?用戶與角色都能去控制
Controller的許可權是否更科學?沒錯,尤其是MVC項目,但是這裡先不考慮這麼多,我們後臺只提供介面服務。這裡我只是提供一個思路,因為要做一個大度的人,只要人進得來,場地自由活動好吧。(就是懶~)
所以會需要使用到授權屬性AuthorizeAttribute類。
- AuthorizeAttribute
AuthorizeAttribute類是.Net Framework框架下提供寫好的一個類,Authorization(授權)屬於過濾器的一種。
這裡可以提下當引用AuthorizeAttribute類時方法的執行過程。當給某一個 Controller 指定一個許可權認證特性後,當程式需要調用這個Controller時,會先進入namespace為System.Web.Http的AuthorizeAttribute公共類,而後首先會執行AuthorizeAttribute 中的 OnAuthorization 方法,在 OnAuthorization 函數的執行過程中,如果驗證失敗了,系統會調用 HandleUnauthorizedRequest方法來進行處理,基於此原理,我們可以重寫這兩個方法,然後自定義自己的AuthorizeAttribute。而如果想提供匿名訪問服務,即調用Controller時不進入AuthorizeAttribute,它提供了AllowAnonymousAttribute屬性,字面意思也知道。
基於上述的執行過程,既然是虛函數,我們重寫他的兩個主要方法。
首先,新建文件夾Filter,文件夾下新建一個繼承於AuthorizeAttribute的類,以XXAuthorizeAttribute命名,XX則就是自定義的特性名稱。我這裡是ApiAuthorizeAttribute。
首先重寫OnAuthorization(HttpActionContext actionContext)。
/// <summary>
/// api許可權特性
/// </summary>
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
public class ApiAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
var authorization = actionContext.Request.Headers.Authorization;
if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0
|| actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0)
{
base.OnAuthorization(actionContext);//正確的訪問方法
}
else
{
if (authorization != null && authorization.Parameter != null)
{this.HandleUnauthorizedRequest(actionContext);//沒有許可權
}
else
{
this.HandleUnauthorizedRequest(actionContext);//沒有許可權
}
}
}
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
base.HandleUnauthorizedRequest(actionContext);
}
}
梳理下邏輯:
首先,通過HttpActionContext 獲得我們在ajax中傳入的Requset.Headers.Authorization.
然後,通過判斷是否有AllowAnonymousAttribute標識。
結合實際場景來理解這一步,還是上文例子。我總不可能一個演唱會主角還沒進場就給保全攔著了要我出示票據???我自己唱歌難道還要自己出錢買票欸?好氣哦是不是?
是的,如果你是保全你就被噴了,那一樣的,如果你是這個項目的開發者,整個項目運行起來就沒一個人能登錄進來,連你自己都進不去,所以考慮實際開發不要反人類邏輯思考,那麼就提供了AllowAnonymousAttribute。通過在控制器上加上[AllowAnonymous],相當於走綠色通道不要門票,那麼這個最應該放在哪呢?
如果沒有關係走不了後門,那麼就老實判斷有無門票。
然後如果沒有,保全趕人,也就是進入HandleUnauthorizedRequest方法,這是會直接將頁面重定向到登錄頁面。當然你要是宅心仁厚是個文化人,不想要保全如此粗魯,自己重寫代碼
返回一段現在最流行的Json數據問問施主可還有其他訴求。
這裡就會涉及到一個問題,WebApi的返回值是不支持的Json格式的,如果又不想更改配置,那麼可以利用HttpResponseMessage返回Json。
return new HttpResponseMessage()
{
Content = new StringContent("string", Encoding.UTF8, "application/json"),
};
這一步做完,是不是覺得終於可以進行激動人心的登錄儀式了?
想什麼呢,什麼都沒有。資料庫你都沒有呢朋友。建庫建表都還沒進行呢。
- ORM
- Entity Framework
Object Relational Mapping,對象關係映射。
這個內容很多,這裡使用Entity Framework,畢竟.Net一套。至於為什麼,最直接的就是因為不想寫SQL語句而且安全,這理由還不充分嗎?不行你往你自己用SQL語句寫的登錄網站試試輸入' or 1 = 1 --',看看會不會有驚喜?有驚喜的少年恭喜你真的很適合看我的博客,給個關註給個推薦謝謝嗷。
下個定義:EF是微軟基於ADO .Net而開發的一套跨資料庫的ORM框架(hhhhhh這裡就不做過多贅述了,資料很多,我自己也寫了一個Word文檔,如果全小白自學的可以聯繫我發給你哈哈哈,其實後面會單獨寫EF的,還會淺談下自學的Entity Framework Core,畢竟我也很菜)
在解決方案Demo下建立Data文件夾,文件夾下新建一個.Net Frameworek的類庫,取名Domain,Domain類庫下建立Models文件夾,此文件夾下建立實體類。
建庫建表時就要考慮到項目需求問題,這點很重要很重要很重要,這也時有無項目經驗的主要體現。加粗加紅好了。
因為是個簡單教程,那麼我這個項目,目前先做個做個能給每個公司提供管理員工,管理自己公司信息報表的簡單平臺。後期縱向橫向發展那些再說。比如加個department表之類的,然後再來個上級管理,下級官吏啊嘖嘖嘖,少年自己沖。
我們先建立簡單的三張表,一張員工表,提供賬號密碼以及簡單個人信息問題。一張賬號信息表,方便記錄一些賬號操作行為。一張公司表,提供基礎信息。
公司與員工的關係,員工與賬號的關係,設置一個公司有一個管理賬號,那麼又有
建表時,考慮到更新性原因,儘量不適用外鍵,所有依賴關係通過自己去思考,比如賬號信息表是不是應該有個用戶ID欄位,以便於進行聯表操作之類,同時對於刪除問題,可以根據不同情景,去考慮使用物理刪除還是邏輯刪除。
這裡簡單提下物理刪除和邏輯刪除的區別:物理刪除是刪除資料庫中的數據,不具有恢復性。而邏輯刪除,不刪除資料庫中的數據,而是通過一些自定義的Flag去判斷,可以理解為黑名單,你可以表格中設置bool 類型欄位deleteSian,為true時可以使用,為false時拉黑,禁用,當需要時可以解除拉黑。
EmployeeModel類:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Demo.Domain.Models
{
[Table("EmployeesInfo")]
public class EmployeesInfoModel
{
[Key]
public int EmployeesID { get; set; }
public int CompanyID { get; set; }
/// <summary>
/// 員工姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Sex { get; set; }
/// <summary>
/// 工號
/// </summary>
public string JobNumber { get; set; }
/// <summary>
/// 員工電話
/// </summary>
public string Mobile { get; set; }
/// <summary>
/// 賬號
/// </summary>
public string AccountNum { get; set; }
/// <summary>
/// 密碼
/// </summary>
public string PassWords { get; set; }
/// <summary>
/// 賬號身份
/// </summary>
public int AccountRole { get; set; }
/// <summary>
/// 員工職位
/// </summary>
public int EmployeeRole { get; set; }
public bool deleteSign { get; set; }
}
}
AccountInfoModel類:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Demo.Domain.Models
{
[Table("AccountInfo")]
public class AccountInfoModel
{
[Key]
public int AccountID { get; set; }
/// <summary>
/// 賬號名
/// </summary>
public string AccountName { get; set; }
public int EmployeesID { get; set; }
/// <summary>
/// 管理查詢
/// </summary>
public int CompanyID { get; set; }
/// <summary>
/// 登陸次數
/// </summary>
public int LoginCount { get; set; }
/// <summary>
/// 開號時間
/// </summary>
public DateTime? CreateTime { get; set; }
public string CreateIP { get; set; }
/// <summary>
/// 最後登陸時間
/// </summary>
public DateTime? LastLoginTime { get; set; }
public string LastLoginIP { get; set; }
}
}
CompanyInfoModel類:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Demo.Domain.Models
{
[Table("CompanyInfo")]
public class CompanyInfoModel
{
/// <summary>
/// 編號
/// </summary>
[Key]
public int CompanyID { get; set; }
/// <summary>
/// 省
/// </summary>
public string Province { get; set; }
/// <summary>
/// 市
/// </summary>
public string City { get; set; }
/// <summary>
/// 區
/// </summary>
public string Area { get; set; }
/// <summary>
/// 全稱
/// </summary>
public string FullName { get; set; }
/// <summary>
/// 組織機構代碼
/// </summary>
public string Organizationcode { get; set; }
public string Mobile { get; set; }
public int Power { get; set; }
public bool deleteSign { get; set; }
}
/// <summary>
/// 管理範圍
/// </summary>
//public enum Power
//{
// 全部 = 0,
// 多區 = 1,
// 單區 = 2
//}
///// <summary>
///// 賬號身份
///// </summary>
//public enum AccountRole
//{
// 管理登錄 = 0,
// 普通登錄 = 1
//}
///// <summary>
///// 員工身份
///// </summary>
//public enum EmployeeRole
//{
// 部門主管 = 0,
// 普通員工 = 1
//}
}
也可以使用枚舉,這裡我還是沒用了。但是意思就是這麼個意思哈哈哈哈。
通過EF建庫建表完成之後,是不是覺得終於可以進行激動人心的登錄儀式了?
對的,沒錯。
但是,
最近忙,餓了,回家做飯。下回分解。逃。