【WEB API项目实战干货系列】

时间:2022-02-17 07:19:54

这篇我们主要来介绍我们如何在API项目中完成API的登录及身份认证. 所以这篇会分为两部分, 登录API, API身份验证.

这一篇的主要原理是: API会提供一个单独的登录API, 通过用户名,密码来产生一个SessionKey, SessionKey具有过期时间的特点, 系统会记录这个SessionKey, 在后续的每次的API返回的时候,客户端需带上这个Sessionkey, API端会验证这个SessionKey.

登录API

我们先来看一下登录API的方法签名

SessionObject是登录之后,给客户端传回的对象, 里面包含了SessionKey及当前登录的用户的信息

这里每次的API调用,都需要传SessionKey过去, SessionKey代表了用户的身份信息,及登录过期信息。

登录阶段生成的SessionKey我们需要做保存,存储到一个叫做UserDevice的对象里面, 从语意上可以知道用户通过不同的设备登录会产生不同的UserDevice对象.

最终的登录代码如下:

[RoutePrefix("api/accounts")] public class AccountController : ApiController { private readonly IAuthenticationService _authenticationService = null; public AccountController() { //this._authenticationService = IocManager.Intance.Reslove<IAuthenticationService>(); } [HttpGet] public void AccountsAPI() { } /// <summary> /// 登录API /// </summary> /// <param>登录帐号(邮箱或者其他LoginID)</param> /// <param>加密后的密码,这里避免明文,客户端加密后传到API端</param> /// <param>客户端的设备类型</param> /// <param>客户端识别号, 一般在APP上会有一个客户端识别号</param> /// <remarks>其他的登录位置啥的,是要客户端能传的东西,都可以在这里扩展进来</remarks> /// <returns></returns> [Route("account/login")] public SessionObject Login(string loginIdorEmail, string hashedPassword, int deviceType = 0, string clientId = "") { if (string.IsNullOrEmpty(loginIdorEmail)) throw new ApiException("username can‘t be empty.", "RequireParameter_username"); if (string.IsNullOrEmpty(hashedPassword)) throw new ApiException("hashedPassword can‘t be empty.", "RequireParameter_hashedPassword"); int timeout = 60; var nowUser = _authenticationService.GetUserByLoginId(loginIdorEmail); if (nowUser == null) throw new ApiException("Account Not Exists", "Account_NotExits"); #region Verify Password if (!string.Equals(nowUser.Password, hashedPassword)) { throw new ApiException("Wrong Password", "Account_WrongPassword"); } #endregion if (!nowUser.IsActive) throw new ApiException("The user is inactive.", "InactiveUser"); UserDevice existsDevice = _authenticationService.GetUserDevice(nowUser.UserId, deviceType);// Session.QueryOver<UserDevice>().Where(x => x.AccountId == nowAccount.Id && x.DeviceType == deviceType).SingleOrDefault(); if (existsDevice == null) { string passkey = MD5CryptoProvider.GetMD5Hash(nowUser.UserId + nowUser.LoginName + DateTime.UtcNow.ToString() + Guid.NewGuid().ToString()); 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 }; } }

API身份验证

身份信息的认证是通过Web API 的 ActionFilter来实现的, 每各需要身份验证的API请求都会要求客户端传一个SessionKey在URL里面丢过来。

在这里我们通过一个自定义的SessionValidateAttribute来做客户端的身份验证, 其继承自 System.Web.Http.Filters.ActionFilterAttribute, 把这个Attribute加在每个需要做身份验证的ApiControler上面,这样该 Controller下面的所有Action都将拥有身份验证的功能, 这里会存在如果有少量的API不需要身份验证,那该如何处理,这个会做一些排除,,为了保持文章的思路清晰,这会在后续的章节再说明.