一、token認證json
服務端登陸成功後分配token字符串。記錄緩存服務器,可設置有效期api
var token = Guid.NewGuid().ToString().Replace("-", ""); var expire = DateTime.Now.AddHours(2); var timespan = ( expire- DateTime.Now); var key = string.Format("login-{0}", apiRm.Result.UserID); RedisCacheHelper.SetCacheByKey<string>(key, JsonHelper.ToJson(apiRm.Result), timespan);
經過header傳入token後進行服務端認證有效性緩存
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'token: 1000-e0622f06a9a842a5b79a5295e6d4b235' -d
在controller或action可設置屬性是否要驗證token服務器
controller:[RoutePrefix("api/Out"), OperateTrack, AuthToken(AuthTypeEnum.Driver)]
或
action:[HttpPost, Route("GetOutInfo"),AuthToken(AuthTypeEnum.Driver)]
讀取過濾器傳過來的信息:
var user = ControllerContext.RouteData.Values["user"];
var user1 = HttpContext.Current.User;
建立AuthTokenAttribute繼承AuthorizeAttributeapp
public class AuthTokenAttribute : AuthorizeAttribute { public AuthTypeEnum VerifyAuth { get; set; } public AuthTokenAttribute() { this.VerifyAuth = AuthTypeEnum.Common; } public AuthTokenAttribute(AuthTypeEnum verifyAuth) { this.VerifyAuth = verifyAuth; } protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext) { var request = actionContext.Request; if(VerifyAuth== AuthTypeEnum.Driver) { var rm= AuthDriver(actionContext); if (!rm.IsSuccess) return false; } return true; } protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext) { StringBuilder sbMsg = new StringBuilder(); if (VerifyAuth == AuthTypeEnum.Driver) { var rm = AuthDriver(actionContext); if (!rm.IsSuccess) sbMsg.Append(rm.Message); } var content = JsonConvert.SerializeObject(new ResultApiModel { IsSuccess = false, Message = sbMsg.ToString() + ",驗證失敗,狀態:" + (int)HttpStatusCode.Unauthorized, Code = ((int)HttpStatusCode.Unauthorized).ToString() }); actionContext.Response = new HttpResponseMessage { Content = new StringContent(content, Encoding.UTF8, "application/json"), StatusCode = HttpStatusCode.Unauthorized }; } private ResultApiModel AuthDriver(System.Web.Http.Controllers.HttpActionContext actionContext) { //todo 驗證token //向action傳值,在action中能夠使用:var user = ControllerContext.RouteData.Values["user"];獲取到 actionContext.ControllerContext.RouteData.Values["user"] = v; SetPrincipal(new UserPrincipal<int>(tokenV)); return ResultApiModel.Create(true); } public static void SetPrincipal(IPrincipal principal) { Thread.CurrentPrincipal = principal; //每次都從新覆蓋user,避免不一樣用戶對不一樣action的訪問 if (HttpContext.Current != null) { HttpContext.Current.User = principal; } } } public enum AuthTypeEnum { Common=0, Driver=1 }
IPrincipal:
public class UserIdentity<TKey> : IIdentity { public UserIdentity(IUser<TKey> user) { if (user != null) { IsAuthenticated = true; UserID = user.UserID; LoginNo = user.LoginNo.ToString(); Name = user.LoginNo.ToString(); UserName = user.UserName; RoleCode = user.RoleCode; token = user.token; } } public string AuthenticationType { get { return "CustomAuthentication"; } } public TKey UserID { get; private set; } public bool IsAuthenticated { get; private set; } public string LoginNo { get; private set; } public string Name { get; private set; } public string UserName { get; private set; } public string RoleCode { get; private set; } public string token { get; private set; } } public class UserPrincipal<TKey> : IPrincipal { public UserPrincipal(UserIdentity<TKey> identity) { Identity = identity; } public UserPrincipal(IUser<TKey> user) : this(new UserIdentity<TKey>(user)) { } /// <summary> /// /// </summary> public UserIdentity<TKey> Identity { get; private set; } IIdentity IPrincipal.Identity { get { return Identity; } } bool IPrincipal.IsInRole(string role) { throw new NotImplementedException(); } } public interface IUser<T> { /// <summary> /// 用戶id /// </summary> T UserID { get; set; } /// <summary> /// 登陸帳號 /// </summary> string LoginNo { get; set; } /// <summary> /// 用戶名稱 /// </summary> string UserName { get; set; } /// <summary> /// 角色編號 /// </summary> string RoleCode { get; set; } /// <summary> /// 登陸後分配token /// </summary> string token { get; set; } }
二、驗證簽名:curl
約定簽名規則ide
controller或action增長屬性驗證ui
[AuthSign(AuthSignTypeEnum.Common)]
建立AuthSignAttribute繼承AuthorizeAttributethis
public class AuthSignAttribute : AuthorizeAttribute { public AuthSignTypeEnum AuthSignType { get; set; } public AuthSignAttribute() { this.AuthSignType = AuthSignTypeEnum.Common; } public AuthSignAttribute(AuthSignTypeEnum authSignType) { this.AuthSignType = authSignType; } /// <summary> /// 公共請求主體數據 /// </summary> private string CommonRequestBodyData { get; set; } /// <summary> /// 權限驗證 /// </summary> /// <param name="actionContext"></param> /// <returns></returns> protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext) { var request = actionContext.Request; var requestBodyData = StreamHelper.GetStream2String(request.Content.ReadAsStreamAsync().Result); if (AuthSignType == AuthSignTypeEnum.Common) { CommonRequestBodyData = requestBodyData.TrimStart("data=".ToCharArray()); var urlParam = GetUrlParam(actionContext); if (!urlParam.IsSuccess) return false; var rm = AuthSignCommon(urlParam.Result, CommonRequestBodyData); if (!rm.IsSuccess) return false; } return true; } private ResultApiModel AuthSignCommon(CommonRequestApiModel request, string requestBodyData) { //todo 驗證signreturn ResultApiModel.Create(true); }/// <summary> /// 處理未受權的請求 /// </summary> /// <param name="actionContext"></param> protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext) { StringBuilder sbMsg = new StringBuilder(); if (AuthSignType == AuthSignTypeEnum.Common) { //todo 處理驗證失敗信息 } var content = JsonConvert.SerializeObject(new ResultApiModel { IsSuccess = false, Message = sbMsg.ToString() + " 簽名驗證失敗,狀態:" + HttpStatusCode.Unauthorized }); actionContext.Response = new HttpResponseMessage { Content = new StringContent(content, Encoding.UTF8, "application/json"), StatusCode = HttpStatusCode.Unauthorized }; } } /// <summary> /// 簽名類型 /// </summary> public enum AuthSignTypeEnum { Common = 0 }
三、訪問日誌:url
controller或action增長屬性
[RoutePrefix("api/Out"), OperateTrack, AuthToken(AuthTypeEnum.Driver)]
不須要日誌能夠[NoLog]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)] public class NoLogAttribute : Attribute { }
繼承:ActionFilterAttribute
public class OperateTrackAttribute : ActionFilterAttribute { /// <summary> /// 自定義參數 /// </summary> public string msg { get; set; } public OperateTrackAttribute() { } /// <summary> /// 初始化時填入類的說明 /// </summary> /// <param name="message"></param> public OperateTrackAttribute(string message) { msg = message; } private static readonly string key = "enterTime"; public override Task OnActionExecutingAsync(System.Web.Http.Controllers.HttpActionContext actionContext, CancellationToken cancellationToken) { if (SkipLogging(actionContext)) { return base.OnActionExecutingAsync(actionContext, cancellationToken); } //記錄進入請求的時間 actionContext.Request.Properties[key] = DateTime.Now.ToBinary(); return base.OnActionExecutingAsync(actionContext, cancellationToken); } /// <summary> /// 在請求執行完後 記錄請求的數據以及返回數據 /// </summary> /// <param name="actionExecutedContext"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public override Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken) { object beginTime = null; if (actionExecutedContext.Request.Properties.TryGetValue(key, out beginTime)) { DateTime time = DateTime.FromBinary(Convert.ToInt64(beginTime)); HttpRequest request = HttpContext.Current.Request; string token = request.Headers["token"]; WebApiActionLogModel apiActionLog = new WebApiActionLogModel { Id = Guid.NewGuid(), //獲取action名稱 actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName, //獲取Controller 名稱 controllerName = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName, //獲取action開始執行的時間 enterTime = time, //獲取執行action的耗時 costTime = (DateTime.Now - time).TotalMilliseconds, navigator = request.UserAgent, token = token, //獲取用戶token userId = getUserByToken(token), //獲取訪問的ip ip = request.UserHostAddress, userHostName = request.UserHostName, urlReferrer = request.UrlReferrer != null ? request.UrlReferrer.AbsoluteUri : "", browser = request.Browser.Browser + " - " + request.Browser.Version + " - " + request.Browser.Type, //獲取request提交的參數 paramaters = StreamHelper.GetStream2String(actionExecutedContext.Request.Content.ReadAsStreamAsync().Result), //獲取response響應的結果 executeResult = StreamHelper.GetStream2String(actionExecutedContext.Response.Content.ReadAsStreamAsync().Result), comments = msg, RequestUri = request.Url.AbsoluteUri }; //記debug Log.DefaultLogDebug(string.Format("actionExecutedContext {0} 請求:{1}", apiActionLog.controllerName + "/" + apiActionLog.actionName, JsonHelper.ToJson(apiActionLog))); } return base.OnActionExecutedAsync(actionExecutedContext, cancellationToken); } /// <summary> /// 獲取當前登陸用戶的id /// </summary> /// <param name="token"></param> /// <returns></returns> public static string getUserByToken(string token) { UserIdentity<int> u = HttpContext.Current.User.Identity as UserIdentity<int>; if (u == null) return "未登陸用戶" + token; return u.LoginNo.ToString(); } /// <summary> /// 判斷類和方法頭上的特性是否要進行Action攔截 /// </summary> /// <param name="actionContext"></param> /// <returns></returns> private static bool SkipLogging(System.Web.Http.Controllers.HttpActionContext actionContext) { return actionContext.ActionDescriptor.GetCustomAttributes<NoLogAttribute>().Any() || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<NoLogAttribute>().Any(); } }