使用Session实现WEB API的授权管理

最近在搞一个基于WEB API的项目,因为之前没接触过这块,所以走了很多弯路。现在把之前实现授权管理的思路记录一下。

(1)URL里带一个GUID当作令牌

用户输入用户名和密码,提交至api/login/login,API确认身份后在传回的HttpResponseMessage里带一个随机的GUID,服务器上有一个List存放这个ID和用户的对应关系。之后每次访问API时需要提交这个ID作为URL参数,API中使用一个公用方法进行验证。

        public static bool LegalRequest(string id)
        {//判断客户端提供的令牌是否合法,每次执行时清理无效令牌
            var delete = IdentityList.Where(tb => tb.InvalidTime <= DateTime.Now).ToList();
            foreach (var a in delete)
            {
                IdentityList.Remove(a);
            }
            bool isLegal = false;
            if (id == null)
                return isLegal;
            Guid identity = Guid.Empty;
            Guid.TryParse(id, out identity);
            if (identity == Guid.Empty)
                return isLegal;
            if (IdentityList.Where(tb => tb.IdentityID == identity).ToList().Count > 0)
                isLegal = true;
            return isLegal;
        }

这个方式可以拦截未授权的访问,但问题是所有的API以及访问API的地方都要添加相应的代码,而且安全性很低(只要拦截这个ID然后自己拼一个URL就可以绕过登陆)。所以后来改代码的时候用了别的方案。

(2)自定义Cookie+过滤器

后来网上找资料的时候学了过滤器(Filter)的使用方法,果断加到项目里。(http://www.cnblogs.com/Flyear/p/4875066.html)

基本逻辑是登录成功的时候生成一个票据,加密以后存到COOKIE里面。每次请求API的时候在HTTP请求里面带上这个COOKIE,然后在ActionFilterAttribute里对票据进行验证。

        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            try
            {
                if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0)
                {//过滤允许匿名访问的action
                    base.OnActionExecuting(actionContext);
                    return;
                }
                var a = actionContext.Request.Headers;
                var cookie = a.GetCookies();//获取Cookies
                if (cookie == null || cookie.Count < 1)
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                    return;
                }

                FormsAuthenticationTicket ticket = null;
                //遍历Cookies,获取验证Cookies并解密
                foreach (var perCookie in cookie[0].Cookies)
                {
                    if (perCookie.Name == FormsAuthentication.FormsCookieName)
                    {
                        ticket = FormsAuthentication.Decrypt(perCookie.Value);
                        break;
                    }
                }
                if (ticket == null)
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                    return;
                }

                if (ticket.Expired)
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                    return;
                }

                if (合法)//去数据库里验证
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                    return;
                }


                //if (actionContext.Response.StatusCode!= HttpStatusCode.Accepted)
                //{
                //    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                //    return;
                //}

                // TODO: 添加其它验证方法

                base.OnActionExecuting(actionContext);
            }
            catch
            {
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
            }
        }

其实这么做和第一种方法差不多,不过拦截和重发cookie的难度稍微大一点点。。。

(3)Session

后来用Fiddler测试API的时候发现,WEB端每次登陆的时候会传一个.NET自带的Cookie(ASP.NET_SessionId),我想了一下,直接用这个Cookie来做身份验证不就省事了。API在登录成功后添加一条Session(同时会自动在context.Request.Cookies里面添加上面的Cookie)客户端提交这个Cookie,API收到Cookie就可以直接从Session中获取用户信息。

//API:登录成功以后添加Session                    
var context = HttpContext.Current;
                    context.Session["user"] = userinfo[0].F_UserName;
                    context.Session["userid"] = userinfo[0].F_UserID;
//WEB端后台:获取登陆成功信息以后修改Cookie
                    Response.Cookies.Clear();
                    if (response.Headers["Set-Cookie"] != null)
                    {
                        var s = response.Headers["Set-Cookie"].Split(';')[0].Split('=');
                        Response.Cookies.Add(new HttpCookie(s[0], s[1]));
                    }//设置cookie为API上的sessioncookie
//API:获取用户信息
Guid.TryParse(HttpContext.Current.Session["userid"].ToString(), out user);//这个代码既可以用来验证身份也可以用来获取用户信息
这个地方实现的时候有一点很坑,就是我项目里的WEB API 和WEB端是放一块的,但是Login页面提交的时候会自带一个SessionID,这个ID和API里的不一样,所以Login页面的后台在登录成功以后要清空原有的Cookie,然后把API返回的Cookie添加进去,而且Login页面的后台还要再添加一次Session供WEB端使用。至于Winform和Android端直接在提交HTTP请求的时候带上这个Cookie就行了。

这种方式不需要自己写很多代码,虽然仍然无法防御重放攻击,不过对于一般的应用已经足够了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值