• WebApi 通过身份票据进行认证授权的具体实现


    写在前面:

    如果webapi接口没有身份认证,那么所有知道接口url的用户都可以随意访问接口,从而查询或者修改数据库,

    那么问题就来了,如果我们不想让所有人都调用我们的接口,那么就需要加上一层验证,只让那些带着正确票据信息的请求来访问webapi接口

     

    跟mvc一样,webapi大多通过附加Authorize特性来实现验证票据信息进行授权,在做这些之前我们先了解一下这个所谓的Authorize的特性:

    首先我们需要用的webApi下的授权筛选AuthorizeAttribute为System.Web.Http.AuthorizeAttribute, 而不是Mvc下用的System.Web.Mvc.AuthorizeAttribute,这点要分清楚

    那么就来说一下AuthorizeAttribute类

    1,AuthorizeAttribute类有一个IsAuthorized方法,用来指示指定的访问是否通过授权, 我们通过该方法为访问请求进行授权

    2,AuthorizeAttribute类中的OnAuthorization方法是一个可以进行重写的方法,该方法的作用就是验证身份票据是否通过,如果验证通过,我们便通过IsAuthorized方法为该请求进行授权,如果不通过则通过HandleUnauthorizedRequest方法处理授权失败的请求

    3,上面说到通过HandleUnauthorizedRequest处理授权失败的请求,那么HandleUnauthorizedRequest这个方法便是我们可以重写的处理授权失败的请求进行的操作

    想必看到这里,大家应该明白了我们用这种方式进行身份票据认证的大概流程,那么我们接下来说一下具体实现的方法:

     

    首先在webapi项目中我们新建一个类,去继承AuthorizeAttribute,重写我们上面说到的OnAuthorizationHandleUnauthorizedRequest方法:

    public class ZyTestAuthorize : AuthorizeAttribute
        {
            /// <summary>
            /// 重写基类的验证方式,加入ticket验证
            /// </summary>
            /// <param name="actionContext"></param>
            public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
            {
                //获取身份票据
                var 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);
                    }
                }
                //如果取不到身份验证信息,并且不允许匿名访问,则返回未验证401  
                else
                {
                    var attributes = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();
                    bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute);
                    if (isAnonymous) base.OnAuthorization(actionContext);
                    else HandleUnauthorizedRequest(actionContext);
                }
            }
    
    
            /// <summary>
            /// 校验票据是否正确
            /// </summary>
            /// <param name="encryptToken"></param>
            /// <returns></returns>
            private bool ValidateTicket(string encryptToken)
            {
                bool flag = false;
                try
                {
                    //从数据库取出对应票据 判断是否对应 切是否在有效期内
                    //--------------省略此处数据库判断------------
                    //如果验证通过 返回true
                    return true;
                }
                catch (Exception ex) { }
                return flag;
            }
    
    
            /// <summary>
            /// 重写处理授权失败方法
            /// </summary>
            /// <param name="filterContext"></param>
            protected override void HandleUnauthorizedRequest(HttpActionContext filterContext)
            {
                base.HandleUnauthorizedRequest(filterContext);
    
                var response = filterContext.Response = filterContext.Response ?? new HttpResponseMessage();
                response.StatusCode = HttpStatusCode.Forbidden;
                //Result类 可自行创建,具体为返回的content信息
                var content = new Result
                {
                    success = false,
                    errs = new[] { "未得授权,禁止访问" }
                };
                response.Content = new StringContent(Json.Encode(content), Encoding.UTF8, "application/json");
            }
        }
    

    接下来需要在我们的具体的webapi接口上添加我们刚刚写好的类的特性:

        [ZyTestAuthorize]
        public class ZyTestController : ApiController
        {
            [AllowAnonymous]
            public string Get()
            {
                return "23333";
            }
            [HttpPost]
            public ResultDataModel Post([FromBody] TestModel model)
            {
                ResultDataModel rm = new ResultDataModel();
                rm.code = "code";
                rm.datas = JsonConvert.SerializeObject(model);
                rm.msg = "msg";
                return rm;
            }
        }
    

    以上这些便是添加身份票据验证的具体实现  

    但是我们发现上面这个示例的webapi接口中除了我们刚才写的ZyTestAuthorize这个类的特性还有一个AllowAnonymous特性,这个特性是用来干什么的呢

    有些时候 我们的webapi中其中的某些接口是不想添加身份验证的,那么AllowAnonymous特性就是解决这个问题的,在方法上添加该特性,则会绕过身份验证可直接进行访问

     

    以上便是我们今天所要说的webapi身份认证的具体实现方式,下面我们看一下js的具体调用方式:

    $("#btnTest").click(function () {
            var model = { name: "name", value: "val" };//post数据
            var token = "233333";//身份票据
            $.ajax({
                url: "http://localhost:2643/ZyTest",
                type: "POST",
                data: model,
                //在beforeSend方法中设置身份票据
                beforeSend: function (request) {
                    request.setRequestHeader('Authorization', 'Bearer ' + token);
                },
                success: function (json) {
                    alert("ok");
                    $("#lbTest").text(json);
                },
                error: function (a, b) {
                    alert("error:" + JSON.stringify(a));
                }
            });
        });
    

    使用C#在后台调用的一种方式:

    使用await为了接收到返回结果,ObjectContent需要引用System.Net.Http.Formatting

        private async void ZyTest()
            {
                TestModel m = new TestModel();
                m.Name = "zy";
                m.Value = "alex";
    
                var c = new HttpClient();
                c.BaseAddress = new Uri("http://localhost:2643");
                c.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
                HttpContent content = new ObjectContent<TestModel>(m, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
                var response = await c.PostAsync("/ZyTest", content);
                string result = response.Content.ReadAsStringAsync().Result;
            }

    以上。

    本文是在工作需要的时候,网上搜集文章资料加上自己的浅薄见解所整理出来的,如果有错误或者不合理的地方,还请各位不吝赐教,在下必洗耳恭听。

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    后续补充:

    如果需要在特定的api中获取当前用户的信息

    var Authorization = Request.Headers.Authorization;
    

    目前没找到更好的办法来实现 只能用上面句代码来获取当前请求的token信息 重新解析找到用户信息。

  • 相关阅读:
    <转>Logistic回归总结
    特征选择和降维的区别
    <转>SVM实现之SMO算法
    <转>KMP算法详解
    <转>主成分分析(Principal components analysis)-最大方差解释,最小平方差解释
    <转>与EM相关的两个算法-K-mean算法以及混合高斯模型
    <转>E-M算法
    隐马尔科夫
    机器学习之判别式模型和生成式模型
    复制图片
  • 原文地址:https://www.cnblogs.com/blazeZzz/p/7285362.html
Copyright © 2020-2023  润新知