使用h5开发跨平台APP确保数据安全交互---服务器篇

  从eclipse到android studio的安卓开发经验告诉我原声开发才是硬道理,其实以前很抵触html5开发app的,虽然没有去了解过,但是冥冥中就觉得它运行速度太慢了,加载渲染根本比不上原生开发,并且如果系统与硬件交互比较深的话就更没法使用html5了。一个偶然机会,我开始接触html5开发app,总之各有各的优缺点,如果对资金比较短缺 ,那么久先使用html5开发与一个app凑合着用吧,不过没有想象中的那么垃圾,其实优点还是蛮多的。想学的可以自己 体会一下。

  APP设计之初当然要先考虑安全性问题,并且能够达到高效,我在这里简单分享一下我的做法(查阅网上的资料做的),app需要与服务器进行交互,通过调用服务器提供的api获取数据,并展示出来。如果服务器api接口没有做任何防护,那么会被他人恶意调用,轻者会加重服务器负担,重者可能造成经济损失。

  首先我们需要能够识别调用者是否为合法用户,如果合法,则返回数据,不合法就直接禁止掉。(下边会将登录与未登录情况),服务器端使用的是asp.net web api。客户端发送请求时,加入sign,ts,deviceid...sign=加密算法(ts+deviceid+***),具体方法看个人,服务端获取到这些数据后,在服务端进行判断,如果时间在5分钟以为,或者签名不正确等问题,就立即禁止访问。访问级别设置为三级:1、不需要任何验证,可以随意访问。2、只能自己的客户端能访问,做签名认证。2、登录认证,必须登录才能访问。登录认证使用比较流行的token方法,当用户登录的时候,如果登录成功,服务器按照一定规则生成已串加密字符串作为token,然后发送给客户端,从那以后客户端每次请求数据都需要将token和用户名提交给服务端,有服务端确定是否为合法登录用户,如不是那么客户端跳回到登录页面,重新登录验证。

  1 using System;
  2 using System.Linq;
  3 using System.Net;
  4 using System.Net.Http;
  5 using System.Web.Http.Controllers;
  6 using System.Web.Http.Filters;
  7 using KubuServerBLL;
  8 using yxxrui;
  9
 10 namespace ****Server
 11 {
 12     public class MyApiActionFilter : ActionFilterAttribute
 13     {
 14         public const int NOT_AUTHENTICATION = 1;
 15         public const int NOT_LOGIN = 2;
 16         public const int NEED_LOGIN = 3;
 17         private const string ApiPrivateKey = "aaaaaasdfadfadfgfdgjldfajooilsdkjfad***sfhdjk";//客户端和手机端保持一致
 18         private readonly int _level;
 19
 20         public MyApiActionFilter()
 21         {
 22             _level = NEED_LOGIN;
 23         }
 24         public MyApiActionFilter(int level)
 25         {
 26             _level = level;
 27         }
 28
 29         public override void OnActionExecuting(HttpActionContext context)
 30         {
 31             //三个级别,1、不需要验证  2、需要认证是否来自合法的客户端  3、是否正确登录
 32             switch (_level)
 33             {
 34                 case NOT_AUTHENTICATION:
 35                     break;
 36                 case NOT_LOGIN:
 37                     if (IsForbidden(context))
 38                     {
 39                         context.Response = new HttpResponseMessage(HttpStatusCode.Gone);
 40                     }
 41                     break;
 42                 case NEED_LOGIN:
 43                     if (IsForbidden(context) || IsNotLogin(context))
 44                     {
 45                         context.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
 46                     }
 47                     break;
 48             }
 49             //如果该请求是不合法的,那么禁止
 50             base.OnActionExecuting(context);
 51             //验证通过
 52
 53         }
 54
 55         private readonly UserBll _userBll = new UserBll();
 56         private bool IsNotLogin(HttpActionContext context)
 57         {
 58             try
 59             {
 60                 //获取请求头信息
 61                 var requestHeaders = context.Request.Headers;
 62                 //设备ID
 63                 var usernameH = requestHeaders.Where(d => d.Key == "username").ToList();
 64                 string username = usernameH.Any() ? usernameH.First().Value.ToArray()[0] : "";
 65                 if (string.IsNullOrWhiteSpace(username))
 66                 {
 67                     return true;
 68                 }
 69
 70                 //请求签名
 71                 var tokenH = requestHeaders.Where(d => d.Key == "token").ToList();
 72                 string token = tokenH.Any() ? tokenH.First().Value.ToArray()[0] : "";
 73                 if (string.IsNullOrWhiteSpace(token))
 74                 {
 75                     return true;
 76                 }
 77                 var isLogin = _userBll.CheckToken(username, token);
 78                 return !isLogin;
 79             }
 80             catch
 81             {
 82                 return true;
 83             }
 84         }
 85
 86         /// <summary>
 87         /// 验证请求头
 88         /// </summary>
 89         /// <param name="context"></param>
 90         /// <returns></returns>
 91         private bool IsForbidden(HttpActionContext context)
 92         {
 93             try
 94             {
 95                 //获取请求头信息
 96                 var requestHeaders = context.Request.Headers;
 97                 //设备ID
 98                 var deviceIdH = requestHeaders.Where(d => d.Key == "deviceId").ToList();
 99                 string deviceId = deviceIdH.Any() ? deviceIdH.First().Value.ToArray()[0] : "";
100                 if (string.IsNullOrWhiteSpace(deviceId))
101                 {
102                     return true;
103                 }
104
105                 //请求签名
106                 var signH = requestHeaders.Where(d => d.Key == "sign").ToList();
107                 string sign = signH.Any() ? signH.First().Value.ToArray()[0] : "";
108                 if (string.IsNullOrWhiteSpace(sign))
109                 {
110                     return true;
111                 }
112
113                 //10位时间戳
114                 var tsH = requestHeaders.Where(d => d.Key == "ts").ToList();
115                 string ts = tsH.Any() ? tsH.First().Value.ToArray()[0] : "";
116                 if (string.IsNullOrWhiteSpace(ts) || ts.Length != 10)
117                 {
118                     return true;
119                 }
120
121                 //看看是否失效,前后5分钟
122                 var tsDate = ComHelper.ConvertIntDateTime(ts);
123                 if (tsDate > DateTime.Now.AddMinutes(5) || tsDate < DateTime.Now.AddMinutes(-5))
124                 {
125                     return true;
126                 }
127                 //服务器端生成的Sign
128                 string mysign = ComHelper.To加密(deviceId + ts + ApiPrivateKey);
129                 if (!sign.Equals(mysign, StringComparison.InvariantCultureIgnoreCase))
130                 {
131                     return true;
132                 }
133             }
134             catch
135             {
136                 return true;
137             }
138             return false;
139         }
140     }
141 }  创建上边的类,使用方法如下:
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Net;
 5 using System.Net.Http;
 6 using System.Web.Http;
 7 using ****ServerBLL;
 8 using ****ServerDAL;
 9 using ****ServerModel;
10
11 namespace ****Server.Controllers.Api
12 {
13     public class NameValuesController : ApiController
14     {
15         private readonly NameValuesBll _nameValuesBll = new NameValuesBll();
16
17         [HttpPost]
18         [MyApiActionFilter(2)]//此处设置标签拦截,级别设置为不需要登录
19         public BaseMsg GetUpdateVersion(dynamic obj)
20         {
21             string clientVersion, deviceId;
22             try
23             {
24                 clientVersion = Convert.ToString(obj.clientVersion);
25                 deviceId = Convert.ToString(obj.deviceId);
26             }
27             catch
28             {
29                 return new BaseMsg("信息有误。");
30             }
31
32             var versionObj = _nameValuesBll.GetValueByName("version");
33             var urlObj = _nameValuesBll.GetValueByName("AndroidUrl");
34
35             if (versionObj == null || urlObj == null)
36             {
37                 return new BaseMsg("获取失败,请重试。");
38             }
39             if (versionObj.value != clientVersion)
40             {
41                 return new BaseMsg(new
42                 {
43                     Version = versionObj.value,
44                     AndroidUrl = urlObj.value,
45                     UpdateMemo = versionObj.other
46                 });
47             }
48             return new BaseMsg("noNewVersion","已是最新版,不需要更新。",null);
49         }
50     }
51 }
上边的方法是一个检查软件是否需要更新的接口,此方法放到服务器可以实现灰度更新,但可能会加重服务器负担。如果app需要检查更新的时候,直接调用该api即可。此接口需要签名认证。  如果希望有一个接口必须由自己做的客户端发出,并且用户成功登录过才可以访问,那么可以将方法上边的标签[MyApiActionFilter(2)]中的数字改成3或者直接删掉即可,如:
 1      #region 绑定手机号码
 2         [HttpPost]
 3         [MyApiActionFilter]
 4         public BaseMsg BindingPhone(dynamic obj)
 5         {
 6             string phone;
 7             string username;
 8             try
 9             {
10                 phone = Convert.ToString(obj.phone);
11                 username = Convert.ToString(obj.username);
12             }
13             catch
14             {
15                 return new BaseMsg("信息有误。");
16             }
17             bool ret = _userBll.BindingPhone(username,phone);
18             if (ret)
19             {
20                 return new BaseMsg();
21             }
22             return new BaseMsg(@"该手机号已经注册过。");
23         }
24         #endregion

   如果控制器中的所有api方法都需要登录后才能使用,那么将标签放到类上方,如果有n个控制器都需要登录后访问,那么创建一个基类去继承ApiController,在该类上边写上标签,然后其他控制器继承该基类,即可快速实现所需功能。至此,服务器端接口就被简单保护起来了。客户端的代码实现等下一篇再写吧。

时间: 2024-10-13 11:48:24

使用h5开发跨平台APP确保数据安全交互---服务器篇的相关文章

带你从零学ReactNative开发跨平台App开发(二)

ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 上一篇教程我们一步步配置了开发RN的必备环境,这篇文章我们依然配置环境,昨天配置的是CRNA模式开发的环境,我们今天配置原生混合开发环境. 第一次写系列教程,写的不好,多多担待,有错误欢迎评判指正. 说一下这个系列教程的目标吧,实战一个CRNA模式开发的跨平台App打包并发布,并将这个App用原生混合开模式实现并打包发布. 废话不多说开始撸码,你准备好了吗? 环境配置 配置原生混合模式开发的环

Sublime用户如何快速高效开发跨平台App

2015年9月15日,APICloud举办了一周年开源分享会,发布开源插件支持Sublime用户开发跨平台App,APICloud 开源技术负责人周兴海分享了Sublime关于插件方面相关的内容. Sublime是一款关注度很高的的开发工具,有以下几个特点: 主流前端开发编辑器 体积较小,运行速度快 文本功能强大 支持编译功能且可在控制台看到输出 内嵌python解释器支持插件开发以达到可扩展目的 Package Control:ST支持的大量插件可通过其进行管理 接着,周兴海对APICloud

开发者技术分享日:如何快速开发跨平台App

活动概况 时间:2014年12月20日14:00-17:00 地点:车库咖啡(北京市海淀西大街48号鑫鼎宾馆二层) 主办:APICloud 活动背景 在这个移动.云.大数据的时代背景下,人人口中都离不开“App”这个热门名词,然而如何降低App开发难度,减少成本,提高效率成为创业者和开发者尤为关注的内容.作为Web圈里的人想进来,但无奈技术门槛和人力成本太高:作为Native开发圈里的人又想出去,但无奈WebApp体验太差,面对当前的现状如何轻松突破App开发难题是这次沙龙交流的主题. 这次沙龙

带你从零学ReactNative开发跨平台App开发(五)

ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发跨平台App开发(三) 带你从零学ReactNative开发跨平台App开发(四) 带你从零学ReactNative开发跨平台App开发(五) 其实写到第三篇的时候,再写第四篇,我突然感到再往后写,好 艰难 啊,坚持,我坚持写,坚持就是胜利,有人说你写这干什么,我说爱好而已,就好比有的人喜欢打王者,

带你从零学ReactNative开发跨平台App开发(十)

ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发跨平台App开发(三) 带你从零学ReactNative开发跨平台App开发(四) 带你从零学ReactNative开发跨平台App开发(五) 带你从零学ReactNative开发跨平台App开发(六) 带你从零学ReactNative开发跨平台App开发(七) hot:更多>> 贴一个交流群的二

带你从零学ReactNative开发跨平台App开发(十三)

ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发跨平台App开发(三) 带你从零学ReactNative开发跨平台App开发(四) 带你从零学ReactNative开发跨平台App开发(五) 带你从零学ReactNative开发跨平台App开发(六) 带你从零学ReactNative开发跨平台App开发(七) hot:更多>> 好久没写了,最近

Sublime插件库新成员基于APICloud快速开发跨平台App

互联网时代强调用户体验,那什么是HTML5跨平台App开发者的编程体验?"不剥夺.不替换开发者喜欢的开发工具,就是人性化的用户体验",APICloud给出了这样的答案! 重磅发布"多开发工具支持策略" "如果,你以为此次分享会APICloud只是讲解Eclipse开源插件代码经验,那就大错特错了!"APICloud CEO刘鑫以调侃的话进行了开场. 经过一年的上线摸索,APICloud团队充分的认识到"剥夺开发者已经习惯的开发工具,替换

带你从零学ReactNative开发跨平台App开发(一)

首先自我介绍一下,本人鸟窝,现在就职于xx共享汽车,担任主程,目前用的技术栈是.net core+angular. 今天我讲的是关于ReactNative从零基础开发,希望可以对入门的新手,起到一个指导作用. 目前学习React Native跨平台开发的人员比较多,干ReactNative开发的程序员,转行过来的也比较多,之前就有遇到过,比如:干前端的,干Android/IOS的,干后台的(C#,Go,Java...PHP),发现一个很有趣的现象,我公司同事干PHP的,一次偶然,我发现他尽然学起

Delphi 10.1.2 berlin开发跨平台APP的几点经验

1.ios不允许app有退出功能,所以不能调用Application.Terminate. 2.info.plist文件的自定义:info.plist文件是由info.plist.TemplateiOS.xml生成的,如果需要定制info.plist内容,则修改info.plist.TemplateiOS.xml即可 3.界面文字的大小建议使用13,统一android与ios的显示,我在android下用12,生成ios app时,发现小些. 4.使用TFrame来做界面,感觉效率比Form要好