anglarjs1.6.3+owin 實現驗證之一:統一拒絕非登陸訪問。

一、anglarjs端在app.js(即anglar的入口js),註冊.factory("messageService",使得每次來自html客戶端的請求都能帶有一個值,如AKey:html

 
 
var chars = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
function generateMixed(n) {
var res = "";
for(var i = 0; i < n ; i ++) {
var id = Math.ceil(Math.random()*35);
res += chars[id];
}
return res;
}var ClientID=generateMixed(6);

var
Akey='ccc'; expressApp.factory('authInterceptor', function($rootScope){ return { request: function(config){ config.headers = config.headers || {}; config.headers.authorization = Akey; return config; }, responseError: function(response){ if(response.status==403) { debugger location.href="./E403.html" } } }; }) expressApp.config(function ($locationProvider, $routeProvider,$httpProvider) { $httpProvider.interceptors.push('authInterceptor'); }

二、html客戶端作一個403頁面,頁面帶一個鏈接,鏈接跳轉到登陸頁redis

<li> 使用具備訪問權限的帳戶從新登陸系統,點擊: <a href="./index.html#/login">此處</a></li>

三、客戶端包含一個登陸頁login.html,對應的關鍵js以下:express

$http({ method: 'post', url: baseUrl+'account/login', data: { LoginName: $scope.LoginName, Password:$scope.Password, ClientID:ClientID } }).then(function (response) { Akey=response.data.LogonUser.SessionKey; }, function (response) { } );

這裏面最重要的一句話,就是Akey=response.data.LogonUser.SessionKey; 由於Aky是在app.js裏面定義的全局變量,因此登陸以前是一個錯誤值,在服務端限定之後,不能訪問任何常規的action,可是隻能訪問服務端的account/login這個action。緩存

四、下來看看服務端的login這個actionsession

[Route("express/account/login")] public HttpResponseMessage Login(Users user) { if (string.IsNullOrEmpty(user.LoginName)) return Request.CreateResponse(HttpStatusCode.Forbidden); if (string.IsNullOrEmpty(user.Password)) return Request.CreateResponse(HttpStatusCode.Forbidden); var nowUser = auS.GetUserByUserId(user.LoginName); if (nowUser == null) return Request.CreateResponse(HttpStatusCode.Forbidden); #region 驗證密碼
    if (!string.Equals(nowUser.Password, user.Password)) { return Request.CreateResponse(HttpStatusCode.Forbidden); } #endregion

    if (nowUser.IsDelete) return Request.CreateResponse(HttpStatusCode.Forbidden); var existsDevice = auS.GetClientUser(nowUser.LoginName); if (existsDevice == null) { string passkey = auS.ComputeHash(nowUser.LoginName + nowUser.ClientID + DateTime.UtcNow + Guid.NewGuid()); existsDevice = new Users() { LoginName = nowUser.LoginName, SessionKey = passkey, ClientID = user.ClientID }; auS.AddClientUser(existsDevice); } else { auS.UpdateUserDevice(existsDevice); } existsDevice.Password = ""; return Request.CreateResponse(HttpStatusCode.OK, new SessionObject() { SessionKey = existsDevice.SessionKey, LogonUser = existsDevice }); }

 這裏面最關鍵的一個就是這兩句話,當客戶端發來一個clientID之後,使用必定的規則合成一個會話ID,存到內存中一個靜態列表裏面,以實現只要登陸一次且不超時,就緩存這我的的登陸信息,至關於session同樣的效果。app

string passkey = auS.ComputeHash(nowUser.LoginName + nowUser.ClientID + DateTime.UtcNow + Guid.NewGuid()); ClientID = user.ClientID

那麼在來看看app.js裏面的這個ClientID:dom

var chars = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']; function generateMixed(n) { var res = ""; for(var i = 0; i < n ; i ++) { var id = Math.ceil(Math.random()*35); res += chars[id]; } return res; } var ClientID=generateMixed(6);

五、來看看AuthenticationService.cs的一些關鍵代碼:這裏也能夠用字典,甚至能夠把列表遷移到redis上面去均可以。ide

public string ComputeHash(string input) { byte[] data = Md5.ComputeHash(Encoding.Unicode.GetBytes(input)); var sBuilder = new StringBuilder(); foreach (byte t in data) sBuilder.Append(t.ToString("X")); return sBuilder.ToString(); } /// <summary>
/// 使用惟一標識得到登陸用戶 /// </summary>
/// <param name="Akey"></param>
/// <returns></returns>
public Users GetClientUserByAkey(string Akey) { //headers.Authorization.Scheme
    var ul = ClientUser.Where(_ => { return _.SessionKey == Akey; }); if (ul != null && ul.Count() > 0) { var u = ul.FirstOrDefault(); if (u.ExpiredTime < DateTime.Now) { return u; } else { ClientUser.Remove(u); } } return null; }

public Users GetUserByUserId(string loginName)
{post

  //Accessor是我寫的一個ORM的訪問器
  var ul = Accessor.GetList<Users>(new { LoginName = loginName });
  return ul.FirstOrDefault();
}ui

 

首先BaseController繼承自ApiController,並且用於登陸的那個Controller也就是AccountController必須繼承自 ApiController

AccountController : ApiController

BaseController: ApiController

再來看看BaseController的關鍵代碼,這樣咱們寫業務Controller(非登陸AccountController)的時候,好比ProductController,讓ProductController:BaseController便可

public Express.Entity.Users currentUser = null; public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) { if (controllerContext.Request.Headers.Authorization != null
        && !string.IsNullOrWhiteSpace(controllerContext.Request.Headers.Authorization.Scheme)) { currentUser = new AuthenticationService().GetClientUserByAkey(controllerContext.Request.Headers.Authorization.Scheme); if (currentUser == null) { var response = new HttpResponseMessage(HttpStatusCode.Forbidden); var tsc = new TaskCompletionSource<HttpResponseMessage>(); tsc.SetResult(response); return tsc.Task; } } else { var response = new HttpResponseMessage(HttpStatusCode.Forbidden); var tsc = new TaskCompletionSource<HttpResponseMessage>(); tsc.SetResult(response); return tsc.Task; } return base.ExecuteAsync(controllerContext, cancellationToken); }

好了,下一篇講述,若是實現粒度到action級別的權限控制。

相關文章
相關標籤/搜索