• ASP.NET WebAPI 双向token实现对接小程序登录逻辑


    最近在学习用asp.net webapi搭建小程序的后台服务,因为基于小程序端和后台二者的通信,不像OAuth(开放授权),存在第三方应用。所以这个token是双向的,一个是对用户的,一个是对接口的。本来做了一份是用Oauth的,用的是第三种密码策略模式。但是因为不存在第三方应用,所以不用Oauth这种授权标准。
    这个Sample是用简单三层做的,书上得来终觉浅,绝知此事要躬行,实践一次就知道wepapi与前端如何通过token认证进行逻辑交互。

    搭建项目

    1. 搭建项目这一点不多说,直接新建一个空的,

    用AuthorizationFilter筛选器完成授权

     为什么会用MVC里用到的AuthorizationFilter呢,具体其实我当时不知道WebAPI里面能不能用,但因为领导说最好小程序访问进来,有一个统一验证的方法。因为我之前在另一个项目里创建了一个控件器基类,BaseController,用于做登录验证,权限验证,日志记录,以及公共方法。因为用了OnActionExecuting,所以当时想也没有想,直接搜索Web API OnActionExecuting,看到Web API也有Filter的相关资料。最后参考了[Web APi之认证(Authentication)]((https://www.cnblogs.com/CreateMyself/p/4857799.html),从而顺利完成了这个双向token认证逻辑。
     首先,在Controllers文件夹里创建AuthFilterAttribute,即自定义Filter特性。这个class里面先重写OnAuthorization方法。
     
     /// <summary>
    /// 最先运行的Filter,被用作请求权限校验
    /// </summary>
    public class AuthFilterAttribute : AuthorizationFilterAttribute
    {
         public override void OnAuthorization(HttpActionContext actionContext)
        {}
    }
    

    Web APi之认证(Authentication)两种实现方式【二】(十三)

    token规则以及解析请求报文头

       OnAuthorization是重写的。那么具体应该写什么呢?当然是进行验证当前的请求是否有授权,是否是 符合要求的请求报文头。
       public override void OnAuthorization(HttpActionContext actionContext)
        {
            //如果用户方位的Action带有AllowAnonymousAttribute,则不进行授权验证
            if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
            {
                return;
            }
            string authParameter = null;
            var authValue = actionContext.Request.Headers.Authorization;//actionContext:Action方法请求上下文
            if (authValue != null && authValue.Scheme == "BasicAuth")//这里有BasicAuth和参考资产里面的不同,我们没有认定类,这里的BasicAuth就算是我们自定义的token规则。其实主要是我还没有了解认证身份以及了解GenericIdentity。
            {
                authParameter = authValue.Parameter;  //获取请求参数
                var authToken = authParameter.Split('|');  //取出参数,参数格式为(当前时间:加密后的token)将其进行分割
                Logging.Error(authParameter);
                if (authToken.Length < 2)
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.NotAcceptable);//参数不完整,返回406不接受
                }
                else
                {
                    
                    //参数完整,进行验证
                    if (ValidateToken(authToken[0],authToken[1]))
                    {
                        base.OnAuthorization(actionContext);
                    }
                    else
                    {
                        actionContext.Response = new HttpResponseMessage(HttpStatusCode.ExpectationFailed);//验证不通过,未满足期望值417
                    }
                }
    
            }
            else
            {
                //如果验证不通过,则返回401错误,并且Body中写入错误原因
                actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, new HttpError("Token 不正确"));
            }
    
        }
    

    token验证

     //验证token
        public bool ValidateToken(string loginTime,string token)
        {
            bool flag = true;
            DateTime checkTime = DateTime.Parse(loginTime);
    
            //先验证时间是否过期
            DateTime nowtime = DateTime.Now;
    
            TimeSpan a = nowtime - checkTime;
    
            Logging.Error("a:"+ a.TotalSeconds);
    
            if (a.TotalSeconds > 120)//时间过期
            {
                flag = false;
            }
            else
            {
                string checkToken = Utils.GetTokenString(loginTime);
                Logging.Error("1:"+checkToken+";2:"+token);
                //比较token
                if (token.Equals(checkToken, StringComparison.CurrentCultureIgnoreCase))
                {
                    flag = true;
                }
                else
                {
                    flag = false;
                }
    
            }
            return flag;
        }
    

    测试请求授权

    1. 新建一个Contorller,添加一个名为Test的Action进行测试
    [HttpGet]
        [Authorize]
        [Route("Test")]
        //public string Test()
        public WxResponseResultModel Test()
        {
            WxResponseResultModel rsEntity = new WxResponseResultModel();
            rsEntity.Code = "200";
            rsEntity.Message = "这是后台传的测试方法";
            //return "这是后台传的测试方法";
            return rsEntity;
        }
    
    1. 前端页面请坟,在本机新建html页面进行测试,token使用了MD5加密方式。
     var keyStr = '123456';
        var timestamp = getMyFormatDate(new Date(),'yyyy-MM-dd hh:mm:ss');//获取当前时间
        console.log("timestamp:" + timestamp);
        var token = hexMD5(keyStr + timestamp);
        console.log("token:" + token);
        var apiServiceBaseUri = "http://localhost:52545/";
        $(function () {
            var data = {code:"25"};
            $.ajax({
                beforeSend: function (xhr) {
                    xhr.setRequestHeader('Authorization', 'BasicAuth ' + timestamp+"|"+token);//token规则
                },
                url: apiServiceBaseUri + 'Login/Test',
                type: "GET",
                dataType: 'json',
                success: function (data) {
                    alert(data.Message);
                    //alert(Message);
                }
            });
        });
    

    首先测试没有[Authorize]的时候,因为最先执行的就是AuthorizationFilter,所以毫无悬念会进入OnAuthorization()进行验证。

    其次,在Test这个Action添加[Authorize]看看,这里会有一个疑问,明明是应该认证的方法,添加了[Authorize]属性,更加应该进入OnAuthorization()才对,为什么会拒绝认证呢?

    这是因为是配置文件中,配置了全局过滤器。
    
    //注册全局Filter
            config.Filters.Add(new AuthFilterAttribute());
    把[Authorize]换成配置的[AuthFilter]属性,就可以成功访问了。
    

    发布IIS,联合小程序测试

    由于小程序对ajax这一块进行了封装,请求统一使用 wx.request请求,使用wx.request加入报文报求的时候,不像ajax这样,写在beforeSend里面。wx.request是写在header里面。token规则在app.js里面做了全局变量调用。
    
     wx.request({
             url: app.globalData.api + 'Login/Test',
             method: "GET",
             header: { 
             'Authorization': app.globalData.header,
             'content-type': 'application/json',
            }, // 设置请求的 header
            success: function (res) {
            //如果是对象的话,写法为
              console.log(res.data.Message);
             // console.log(res.data);
            },
            fail:function(res){
             console.log("fail:" + res)
           }
      });
    

    测试期间出现一个bug,提示如下:
    未能找到 CodeDom 提供程序类型“Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf385

    解决办法参考:

    未能找到 CodeDom 提供程序类型

    参考资料:

    api token参考资料

    api接口token验证

    小程序登录逻辑参考资料

    ASP.NET WebApi作服务端开发小程序实现微信授权用户登录实例——登录逻辑1

    ASP.NET WebApi作服务端开发小程序实现微信授权用户登录实例——登录逻辑2

    ASP.NET WebApi作服务端开发小程序实现微信授权用户登录实例——登录逻辑3

    本文WebAPI源代码

  • 相关阅读:
    黑马程序员面向对象09天1
    一键安装LNMP
    多屏互动技术
    阿里云CentOS 64位解决kernel2.6.32220.13.1.el6.x86_64 has missing requires错误
    listview的onItemClickListener失效
    在阿里云主机上基于CentOS用vsftpd搭建FTP服务器(赚)
    asp.net关于在线支付的实现过程
    C#关闭登录窗体,显示主窗体
    winform 刷新父窗体(转)
    用代码生成器生成的DAL数据访问操作类 基本满足需求了
  • 原文地址:https://www.cnblogs.com/mooncake-wong/p/9728828.html
Copyright © 2020-2023  润新知