WebApi用户登录验证及服务器端用户状态存取
最近项目需要给手机端提供数据,采用WebApi的方式,之前的权限验证设计不是很好,这次采用的是Basic基础认证。
1、常见的认证方式
我们知道,asp.net的认证机制有很多种。对于WebApi也不例外,常见的认证方式有
- FORM身份验证
- 集成WINDOWS验证
- Basic基础认证
- Digest摘要认证
2、Basic基础认证原理
我们知道,认证的目的在于安全,那么如何能保证安全呢?常用的手段自然是加密。Basic认证也不例外,主要原理就是加密用户信息,生成票据,每次请求的时候将票据带过来验证。这样说可能有点抽象,我们详细分解每个步骤:
这个基本的原理。下面就按照这个原理来看看每一步的代码如何实现。
3、Basic基础认证的代码示例
创建缓存类,存储用户状态信息CacheManager类
public class CacheManager{private static Dictionary<String, Object> cache = null;private static CacheManager cacheManager =null;/// <summary>/// 程序运行时,创建一个静态只读的进程辅助对象/// </summary>private static readonly object _object = new object();/// <summary>/// Make sure the class is singleton so only one instance is shared by all. /// </summary>private CacheManager(){cache = new Dictionary<string, object>();}/// <summary>/// Get the singleton instance./// </summary>/// <returns></returns>public static CacheManager instance(){//先判断实例是否存在,不存在再加锁处理if (cacheManager == null){//在同一时刻加了锁的那部分程序只有一个线程可以进入,lock (_object){//如实例不存在,则New一个新实例,否则返回已有实例if (cacheManager == null){cacheManager = new CacheManager();}}}return cacheManager;}/// <summary>/// 添加用户信息/// </summary>/// <param name="key"></param>/// <param name="value"></param>public void add(String key, Object value){if (!cache.ContainsKey(key))cache.Add(key, value);else{remove(key);cache.Add(key, value);}}/// <summary>/// 删除用户状态信息/// </summary>/// <param name="key"></param>public void remove(String key){cache.Remove(key);}/// <summary>/// 初使化缓存/// </summary>public void invalidateCache(){cache = new Dictionary<string, object>();}/// <summary>/// 获取用户状态信息/// </summary>/// <param name="key"></param>/// <returns></returns>public object get(String key){Object obj;if (cache.ContainsKey(key))cache.TryGetValue(key,out obj);else{obj = null;}return obj;}}
在App_Start文件下创建票据认识类RequestAuthorizeAttribute
public class RequestAuthorizeAttribute : AuthorizeAttribute{CacheManager cache = CacheManager.instance();//重写基类的验证方式,加入我们自定义的Ticket验证public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext){//从http请求的头里面获取身份验证信息,验证是否是请求发起方的ticketvar authorization = actionContext.Request.Headers.Authorization;if ((authorization != null) && (authorization.Parameter != null)){//解密用户ticket,并校验用户名密码是否匹配var encryptTicket = authorization.Parameter;if (ValidateTicket(encryptTicket)){base.IsAuthorized(actionContext);}else{HandleUnauthorizedRequest(actionContext);}}//如果取不到身份验证信息,并且不允许匿名访问,则返回未验证401else{var attributes = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute);if (isAnonymous) base.OnAuthorization(actionContext);else HandleUnauthorizedRequest(actionContext);}}//校验用户名密码private bool ValidateTicket(string encryptTicket){//解密Ticketvar strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;//从Ticket里面获取用户名和密码var index = strTicket.IndexOf("&");string strUser = strTicket.Substring(0, index);string strPwd = strTicket.Substring(index + 1);//服务器端判断用户信息object objUmodel = cache.get(strUser);if (objUmodel != null){UserModel u = (UserModel)objUmodel;if (u.UserPwd.Equals(strPwd))return true;elsecache.remove(strUser);return false;}else{return false;}}}
在公共方法中创建获取票据方法
/// <summary>/// 获取票据/// </summary>/// <param name="ticketName">票证名称</param>/// <param name="timeState">票证过期时间</param>/// <param name="userData">票证数据</param>/// <returns></returns>public static FormsAuthenticationTicket GetTicket(string ticketName, int timeState, string userData){FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0, ticketName, DateTime.Now,DateTime.Now.AddMinutes(timeState),true, string.Format("{0}&{1}", ticketName, userData),FormsAuthentication.FormsCookiePath);return ticket;}用户登录时,存入票据
[HttpPost][AllowAnonymous]public object UserLogin([FromBody] UserModel model){Int32 sysRole = 0;Message msg = new Message() { Content = "登录失败,请重新登录!" };if (model==null || string.IsNullOrEmpty(model.UserCode) || string.IsNullOrEmpty(model.UserPwd)){msg.Flag = false;return msg;}string EncryptPwd = PasswordUtility.Md5To32(model.UserPwd);var userModel = user.UserModelByLogin(model.UserCode, EncryptPwd, sysRole);if (userModel != null && userModel.ID > 0){msg.Flag = true;msg.Content = "登录成功!";FormsAuthenticationTicket ticket = Common.GetTicket(userModel.UserCode, timeState, EncryptPwd);//返回登录结果、用户信息、用户验证票据信息var oUser = new UserModel { Flag = true,UserCode= userModel.UserCode,UserImg= userModel.UserImg, UserName = userModel.UserName, UserPwd = EncryptPwd, Ticket = FormsAuthentication.Encrypt(ticket) };msg.ApiData = oUser;cache.add(model.UserCode, oUser);}else{msg.Flag = false;msg.Data = "";}return msg;}
4、WebApi跨域调用方法
因为WebApi涉及到跨域请求,所以在WebConfig中需要加入一段代码,解决跨域问题,Authorization是向http的head里面加入请求票据,否则浏览器请求不成功。
<httpProtocol><customHeaders><add name="Access-Control-Allow-Origin" value="*" /><add name="Access-Control-Allow-Headers" value=" Origin,Content-Type, Accept,Authorization" /><add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" /></customHeaders></httpProtocol>
5、Web页面调用WebApi方法,使用Ajax调用方法
var Ticket;$(function () {$.ajax({type: "post",url: url + "/UserLogin",data: { UserCode: '1002', UserPwd: '123456' },datatype: 'json',success: function (data, status) {if (status == "success") {debugger;if (!data.Flag) {alert("登录失败");return;}alert("登录成功");//登录成功之后将用户名和用户票据带到主界面Ticket = data.ApiData.Ticket;$("#hdTicket").val(Ticket);}},error: function (e) {},complete: function () {}});});function myfunction() {$.ajax({type: "get",url: url + '/GetLoginOut?uid=1002',datatype:'json',beforeSend: function (request) {alert('beforesend:' + Ticket);//发送ajax请求之前向http的head里面加入验证信息request.setRequestHeader('Authorization', 'BasicAuth ' + Ticket);},//xhrFields: {// withCredentials: true//},//crossDomain: true,success: function (data) {alert('success:' + data);},error: function (data) {console.log(data);alert('error:' + data);}});}
跨域请求参考地址:https://www.cnblogs.com/cdemo/p/5158663.html
原为参考地址:https://www.cnblogs.com/landeanfen/p/5287064.html
转载于:https://www.cnblogs.com/personblog/p/8535204.html
总结
以上是生活随笔为你收集整理的WebApi用户登录验证及服务器端用户状态存取的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 20165334 《java程序设计》第
- 下一篇: 图像滤镜艺术--编码基础(Photosh