使用h5開發跨平臺APP確保數據安全交互---伺服器篇

来源:http://www.cnblogs.com/yxxrui/archive/2016/10/12/ApiServerSecurity.html
-Advertisement-
Play Games

從eclipse到android studio的安卓開發經驗告訴我原聲開發才是硬道理,其實以前很抵觸html5開發app的,雖然沒有去瞭解過,但是冥冥中就覺得它運行速度太慢了,載入渲染根本比不上原生開發,並且如果系統與硬體交互比較深的話就更沒法使用html5了。一個偶然機會,我開始接觸html5開發 ...


  從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,在該類上邊寫上標簽,然後其他控制器繼承該基類,即可快速實現所需功能。至此,伺服器端介面就被簡單保護起來了。客戶端的代碼實現等下一篇再寫吧。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目錄 1. ApiController 2. HttpActionDescriptor 3. IHttpActionSelector ApiController 在上節中,講到如何選擇並激活對應的IHttpController,而一般我們在開發中使用的是ApiController 在ApiContr ...
  • 編寫MFC程式時,想列印出調試信息,使用cout後,發現程式並沒有像想象中那樣自動彈出命令行視窗,要輸出的信息也沒地方去查看。百度後知道要手動調出命令行視窗,才可以看到輸出的信息。 百度上介紹了兩種方法,一種是通過添加代碼,在程式中建立命令行視窗的對象。這裡介紹一種比較簡單的方法。 右鍵解決方案,打 ...
  • 1、視圖中 2、控制器的action中 3、過濾器中 比如在ActionFilterAttribute中,這個時候一般是自己實現一個繼承類,然後重寫相關的方法。 在重寫的方法中如果需要控制器的名稱。 4、公共方法中 ...
  • (本文是從我的舊博客遷移過來的) 問題地址:http://acm.timus.ru/problem.aspx?space=1&num=1258 前幾日在博客園看到這種線上測試的時候,有一種相見恨晚的感覺,於是隨便選了一道感興趣的題(No.1258:Pool)開始做。為了準確瞭解題的意思,我把題翻譯成 ...
  • 本次將要很大家分享的是一個跨平臺運行的服務插件 - TaskCore.MainForm,此框架是使用.netcore來寫的,現在netcore已經支持很多系統平臺運行了,所以將以前的Task.MainForm改良成跨平臺的服務共大家使用和相互交流;本來這篇應該分享的是nginx+iis+redis+ ...
  • ...
  • 剖析 AssemblyInfo.cs - 從這裡瞭解常用的特性 Attribute 【博主】反骨仔 【原文】http://www.cnblogs.com/liqingwen/p/5944391.html 序 上次,我們通過《C# 知識回顧 - 特性 Attribute》已經瞭解如何創建和使用特性 A ...
  • 配置 ASP.NET HTTP 運行時設置,以確定如何處理對 ASP.NET 應用程式的請求,配置節及其描述如下所示。 <httpRuntime executionTimeout="110" 指定在被 ASP.NET 自動關閉前,允許執行請求的最大秒數 maxRequestLength="4096" ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...