zoukankan      html  css  js  c++  java
  • 学习总结之 WebApi 用户登录和匿名登录,及权限验证

    近些天,看了一些博客园大牛关于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

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

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

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

  • 相关阅读:
    进程同步
    CPU调度
    线程的引入
    进程互斥
    处理器状态
    操作系统
    进程的基本概念
    socket应用
    html笔记
    HTTP基本链接原理
  • 原文地址:https://www.cnblogs.com/huangenai/p/5253709.html
Copyright © 2011-2022 走看看