0%

近些天,看了一些博客园大牛关于webApi项目的的文章,也有请教师兄一些问题,自己做了个Demo试了试,收获甚多。感谢感谢,下面是我一些学习的总结,如若有错的地方请多多指教!!

WebApi登陆与身份验证

因为在调用接口的时候都必须传sessionKey参数过去,所以必须先登录验证身份。

如果是已注册用户则账号登陆,获得其身份标识的 sessionkey,如果是非账户用户则可以匿名登陆,要输入用户IP地址或者和客户端设备号等以获得sessionkey,然后可以去注册。

 

#region 登录API
///


/// 登录API (账号登陆) ///

/// 登录帐号手机号
/// 加密后的密码,这里避免明文,客户端加密后传到API端
/// 客户端的设备类型
/// 客户端识别号, 一般在APP上会有一个客户端识别号
///
[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获得用户信息
///


/// 根据用户ID获得用户信息(获得数据) ///

/// sessionKey
/// 用户id
/// result
public ApiResult GetUserById( string sessionKey,int id)
{
Users modelUsers = _users.GetUserByUsersId(id); if (modelUsers != null)
{ return new ApiResult(“1”,”获取用户信息成功”,modelUsers);
} else return new ApiResult(“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

此随笔乃本人学习工作记录,如有疑问欢迎在下面评论,转载请标明出处。

如果对您有帮助请动动鼠标右下方给我来个赞,您的支持是我最大的动力。

 2017-11 代码及数据库文件已经上传至 https://github.com/huangenai/WebAPI