近些天,看了一些博客园大牛关于webApi项目的的文章,也有请教师兄一些问题,本身作了个Demo试了试,收获甚多。感谢感谢,下面是我一些学习的总结,如如有错的地方请多多指教!!html
WebApi登录与身份验证git
由于在调用接口的时候都必须传sessionKey参数过去,因此必须先登陆验证身份。github
若是是已注册用户则帐号登录,得到其身份标识的 sessionkey,若是是非帐户用户则能够匿名登录,要输入用户IP地址或者和客户端设备号等以得到sessionkey,而后能够去注册。web
#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
#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。api
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; } } }
须要身份验证的apiControler 上加上[sessionValidate],则这个Controller下面全部Action都将拥有身份验证功能session
若是是须要管理员权限才能请求的数据的话,那么咱们再定义一个 SessionValidateAdminAttribute 来作管理员的身份验证,在须要管理员权限才能请求的控制器上加上[SessionValidateAdminAttribute ],则这个控制器下面全部Action都只有经过身份验证的管理员才有权限请求。cors
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); } } }
关于:[EnableCors(origins: "*", headers: "*", methods: "*")] 的说明,ide
详情查看: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); } }
此随笔乃本人学习工做记录,若有疑问欢迎在下面评论,转载请标明出处。
若是对您有帮助请动动鼠标右下方给我来个赞,您的支持是我最大的动力。
2017-11 代码及数据库文件已经上传至 https://github.com/huangenai/WebAPI