近些天,看了一些博客園大牛關於webApi項目的的文章,也有請教師兄一些問題,自己做了個Demo試了試,收穫甚多。感謝感謝,下麵是我一些學習的總結,如若有錯的地方請多多指教!! WebApi登陸與身份驗證 因為在調用介面的時候都必須傳sessionKey參數過去,所以必須先登錄驗證身份。 如果是已註 ...
近些天,看了一些博客園大牛關於webApi項目的的文章,也有請教師兄一些問題,自己做了個Demo試了試,收穫甚多。感謝感謝,下麵是我一些學習的總結,如若有錯的地方請多多指教!!
WebApi登陸與身份驗證
因為在調用介面的時候都必須傳sessionKey參數過去,所以必須先登錄驗證身份。
如果是已註冊用戶則賬號登陸,獲得其身份標識的 sessionkey,如果是非賬戶用戶則可以匿名登陸,要輸入用戶IP地址或者和客戶端設備號等以獲得sessionkey,然後可以去註冊。
#region 登錄API /// <summary> /// 登錄API (賬號登陸) /// </summary> /// <param name="phone">登錄帳號手機號</param> /// <param name="hashedPassword">加密後的密碼,這裡避免明文,客戶端加密後傳到API端</param> /// <param name="deviceType">客戶端的設備類型</param> /// <param name="clientId">客戶端識別號, 一般在APP上會有一個客戶端識別號</param> /// <returns></returns> [Route("account/login")] public SessionObject Login(string phone, string hashedPassword, int deviceType = 0, string clientId = "") { if (string.IsNullOrEmpty(phone)) throw new ApiException("用戶名不能為空。", "RequireParameter_userphone"); if (string.IsNullOrEmpty(hashedPassword)) throw new ApiException("hashedPassword 不能為空.", "RequireParameter_hashedPassword"); int timeout = 60; var nowUser = _authenticationService.GetUserByPhone(phone); if (nowUser == null) throw new ApiException("帳戶不存在", "Account_NotExits"); #region 驗證密碼 if (!string.Equals(nowUser.Password, hashedPassword)) { throw new ApiException("錯誤的密碼", "Account_WrongPassword"); } #endregion if (!nowUser.IsActive) throw new ApiException("用戶處於非活動狀態.", "InactiveUser"); UserDevice existsDevice = _authenticationService.GetUserDevice(nowUser.UserId, deviceType); if (existsDevice == null) { string passkey = MD5CryptoProvider.GetMD5Hash(nowUser.UserId + nowUser.Phone + DateTime.UtcNow+ Guid.NewGuid()); existsDevice = new UserDevice() { UserId = nowUser.UserId, CreateTime = DateTime.UtcNow, ActiveTime = DateTime.UtcNow, ExpiredTime = DateTime.UtcNow.AddMinutes(timeout), DeviceType = deviceType, SessionKey = passkey }; _authenticationService.AddUserDevice(existsDevice); } else { existsDevice.ActiveTime = DateTime.UtcNow; existsDevice.ExpiredTime = DateTime.UtcNow.AddMinutes(timeout); _authenticationService.UpdateUserDevice(existsDevice); } nowUser.Password = ""; return new SessionObject() { SessionKey = existsDevice.SessionKey, LogonUser = nowUser }; } #endregion登錄API
#region 匿名登陸 /// <summary> /// 匿名登陸 /// </summary> /// <param name="ip">用戶ip地址</param> /// <param name="deviceType">設備類型</param> /// <param name="clientId">客戶端識別號</param> /// <returns></returns> [Route("account/AnonymousLogin")] public SessionObject1 AnonymousLogin(string ip, int deviceType = 0, string clientId = "") { if (string.IsNullOrEmpty(ip))throw new ApiException("ip地址不能為空。", "RequireParameter_ip"); int timeout = 60; UserDevice existsDevice = _authenticationService.GetUserDevice(ip, deviceType); // Session.QueryOver<UserDevice>().Where(x => x.AccountId == nowAccount.Id && x.DeviceType == deviceType).SingleOrDefault(); if (existsDevice == null) { string passkey = MD5CryptoProvider.GetMD5Hash(ip+DateTime.UtcNow + Guid.NewGuid()); existsDevice = new UserDevice() { IP = ip, CreateTime = DateTime.UtcNow, ActiveTime = DateTime.UtcNow, ExpiredTime = DateTime.UtcNow.AddMinutes(timeout), DeviceType = deviceType, SessionKey = passkey }; _authenticationService.AddUserDevice(existsDevice); } else { existsDevice.ActiveTime = DateTime.UtcNow; existsDevice.ExpiredTime = DateTime.UtcNow.AddMinutes(timeout); _authenticationService.UpdateUserDevice(existsDevice); } return new SessionObject1() { SessionKey = existsDevice.SessionKey, Ip=ip }; } #endregion匿名登陸
身份信息的認證是通過Web API 的 ActionFilter來實現的,所有需要身份驗證的API請求都會要求客戶端傳一個SessionKey。
在這裡我們通過一個自定義的SessionValidateAttribute來做客戶端的身份驗證, 其繼承自 System.Web.Http.Filters.ActionFilterAttribute。
public class SessionValidateAttribute : System.Web.Http.Filters.ActionFilterAttribute { public const string SessionKeyName = "SessionKey"; public const string LogonUserName = "LogonUser"; public override void OnActionExecuting(HttpActionContext filterContext) { var qs = HttpUtility.ParseQueryString(filterContext.Request.RequestUri.Query); string sessionKey = qs[SessionKeyName]; if (string.IsNullOrEmpty(sessionKey)) { throw new ApiException("無效 Session.", "InvalidSession"); } IAuthenticationService authenticationService = new AuthenticationService();//IocManager.Intance.Reslove<IAuthenticationService>(); //驗證用戶session var userSession = authenticationService.GetUserDevice(sessionKey); if (userSession == null) { throw new ApiException("無此 sessionKey", "RequireParameter_sessionKey"); } else { //todo: 加Session是否過期的判斷 if (userSession.ExpiredTime < DateTime.UtcNow) throw new ApiException("session已過期", "SessionTimeOut"); var logonUser = authenticationService.GetUser(userSession.UserId); if (logonUser != null) { filterContext.ControllerContext.RouteData.Values[LogonUserName] = logonUser; SetPrincipal(new UserPrincipal<int>(logonUser)); } userSession.ActiveTime = DateTime.UtcNow; userSession.ExpiredTime = DateTime.UtcNow.AddMinutes(60); authenticationService.UpdateUserDevice(userSession); } } public static void SetPrincipal(IPrincipal principal) { Thread.CurrentPrincipal = principal; if (HttpContext.Current != null) { HttpContext.Current.User = principal; } } }API身份驗證
需要身份驗證的apiControler 上加上[sessionValidate],則這個Controller下麵所有Action都將擁有身份驗證功能
如果是需要管理員許可權才能請求的數據的話,那麼我們再定義一個 SessionValidateAdminAttribute 來做管理員的身份驗證,在需要管理員許可權才能請求的控制器上加上[SessionValidateAdminAttribute ],則這個控制器下麵所有Action都只有通過身份驗證的管理員才有許可權請求。
public class SessionValidateAdminAttribute : System.Web.Http.Filters.ActionFilterAttribute { public const string SessionKeyName = "SessionKey"; public const string LogonUserName = "LogonUser"; public override void OnActionExecuting(HttpActionContext filterContext) { var qs = HttpUtility.ParseQueryString(filterContext.Request.RequestUri.Query); string sessionKey = qs[SessionKeyName]; if (string.IsNullOrEmpty(sessionKey)) { throw new ApiException("無效 Session.", "InvalidSession"); } IAuthenticationService authenticationService = new AuthenticationService();//IocManager.Intance.Reslove<IAuthenticationService>(); //驗證用戶session var userSession = authenticationService.GetUserDevice(sessionKey); if (userSession == null) { throw new ApiException("無此 sessionKey", "RequireParameter_sessionKey"); } else { //todo: 加Session是否過期的判斷 if (userSession.ExpiredTime < DateTime.UtcNow) throw new ApiException("session已過期", "SessionTimeOut"); var logonUser = authenticationService.GetUser(userSession.UserId); if (logonUser == null) { throw new ApiException("無此用戶", "Invalid_User"); } else { if (logonUser.Permissions == 1) { filterContext.ControllerContext.RouteData.Values[LogonUserName] = logonUser; SessionValidateAttribute.SetPrincipal(new UserPrincipal<int>(logonUser)); } else { throw new ApiException("用戶無許可權", "No permissions"); } } userSession.ActiveTime = DateTime.UtcNow; userSession.ExpiredTime = DateTime.UtcNow.AddMinutes(60); authenticationService.UpdateUserDevice(userSession); } } }SessionValidateAdminAttribute
關於:[EnableCors(origins: "*", headers: "*", methods: "*")] 的說明,
詳情查看:http://www.cnblogs.com/artech/p/cors-4-asp-net-web-api-05.html
關於用戶過期時間:每次調用介面的時候 會自動更新sessionKey的過期時間,如果長時間未更新,則下次訪問時會過期,則需要重新登陸。
加入身份驗證後的 UserControler
[EnableCors(origins: "*", headers: "*", methods: "*")] [RoutePrefix("api/Users"), SessionValidate, WebApiTracker] public class UsersController : ApiController { private readonly IUsers _users=new UsersImpl(); #region 根據用戶ID獲得用戶信息 /// <summary> /// 根據用戶ID獲得用戶信息(獲得數據) /// </summary> /// <param name="sessionKey">sessionKey</param> /// <param name="id">用戶id</param> /// <returns>result</returns> public ApiResult<Users> GetUserById( string sessionKey,int id) { Users modelUsers = _users.GetUserByUsersId(id); if (modelUsers != null) { return new ApiResult<Users>("1","獲取用戶信息成功",modelUsers); } else return new ApiResult<Users>("0","無此用戶信息",null); } #endregion /// <summary> /// 新用戶註冊(增加數據) /// </summary> /// <param name="modelUsers"></param> /// <returns>result</returns> [HttpPost, Route("api/UserRegistration")] public ApiResult<bool> UserRegistration(string sessionKey, AddUserRq modelUsers) { Users usersModel=new Users(); usersModel.IsActive = true; usersModel.Password = modelUsers.Password; usersModel.Permissions = 2; usersModel.Phone = modelUsers.Phone; usersModel.Sex = modelUsers.Sex; usersModel.TrueName = modelUsers.TrueName; usersModel.UserName = modelUsers.UserName; return _users.RegistrationNewUsers(usersModel); } }UsersControllers