从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,在该类上边写上标签,然后其他控制器继承该基类,即可快速实现所需功能。至此,服务器端接口就被简单保护起来了。客户端的代码实现等下一篇再写吧。

有问题可以联系我,我的邮箱是:yxxrui@163.com,我的网址是:http://www.yxxrui.cn

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

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

    2015年9月15日,APICloud举办了一周年开源分享会,发布开源插件支持Sublime用户开发跨平台App,APICloud 开源技术负责人周兴海分享了Sublime关于插件方面相关的内容. S ...

  2. H5外包团队 H5开发微信APP的优势有哪些

    H5外包团队 H5开发微信APP的优势有哪些

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

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

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

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  5. 带你从零学ReactNative开发跨平台App开发-[react native 仿boss直聘](十三)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

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

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

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

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  8. 带你从零学ReactNative开发跨平台App开发(九)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  9. 带你从零学ReactNative开发跨平台App开发[expo 打包发布](八)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

随机推荐

  1. python3 Redis未授权检测脚本

    `import sys import getopt import socket def get_target(): opts, args = getopt.getopt(sys.argv[1:], ' ...

  2. 机场&代理商-关系图

    机场&代理商-关系图 思路 ①首先统计机场活跃度Top10的机场名称,以下是我的表结构,以及查询语句 表结构: 查询语句:SELECT * from 2020csale ORDER BY cn ...

  3. Network-Emulator-Toolkit 模拟各种网络环境 windows

    背景.目标.目的 (1) 背景: 我们在使用网络时,时常遇到在正常网络环境下的代码运行一切正常,可以复杂的网络环境下的各种问题无法复现,必须搭建模拟各种网络环境,去复现问题,定位问题.不管是移动平台, ...

  4. SQL注入步骤

    1.判断是否存在注入,注入是字符型还是数字型2.猜解SQL查询语句中的字段数3.确定回显的字段数4.获取当前数据库5.获取表中字段名6.下载数据

  5. mysql索引原理以及优化

    一.常见查找算法: 1.顺序查找: 最基础的查找方法,对比每一个元素进行查找.在数据量很大的时候效率相当的慢. 数据结构:有序或者无需的队列 时间复杂度:O(n) 2.二分查找: 二分查找首先要求数组 ...

  6. PyQt(Python+Qt)学习随笔:怎么在QScrollArea滚动区域中展示子部件的超长内容?

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 滚动区域可以针对部署在其上的子部件在不可见时进行滚动展示,但这种滚动展示仅只能展示内容层可见范围的子 ...

  7. CTFHub Web题学习笔记(Web前置技能+信息泄露题解writeup)

    今天CTFHub正式上线了,https://www.ctfhub.com/#/index,之前有看到这个平台,不过没在上面做题,技能树还是很新颖的,不足的是有的方向的题目还没有题目,CTF比赛时间显示 ...

  8. 【C/C++】C和C++11之enum枚举的使用细节

    作者:李春港 出处:https://www.cnblogs.com/lcgbk/p/14101271.html 目录 一.前言 二.C中的枚举(enum) 2.1 C中枚举的大小 2.2 C中枚举的取 ...

  9. Hangfire&Autofac与ASP.NET CORE注入失败

    Hangfire.Autofac与ASP.NET CORE注入失败 项目里面使用了Hangfire,因为之前没用过吧,遇到了个问题,就是使用了ico容器后,再用Hangfire总是注入不上对象,总是后 ...

  10. nginx转发上传图片接口图片的时候,报错413

    我这边有一个接口是上传图片,使用nginx进行代理,上传大一点的图片,直接调用我的接口不会报错,但是调用nginx上传图片就会报错"413 Request Entity Too Large& ...