在app開放接口api的設計中,避免不了的就是安全性問題,由於大多數接口涉及到用戶的我的信息以及一些敏感的數據,因此對這些接口須要進行身份的認證,那麼這就須要用戶提供一些信息,好比用戶名密碼等,可是爲了安全起見讓用戶暴露的明文密碼次數越少越好,咱們通常在web項目中,大多數採用保存的session中,而後在存一份到cookie中,來保持用戶的回話有效性。可是在app提供的開放接口中,後端服務器在用戶登陸後如何去驗證和維護用戶的登錄有效性呢,如下是參考項目中設計的解決方案,其原理和大多數開放接口安全驗證同樣,如淘寶的開放接口token驗證,微信開發平臺token驗證都是同理。html
對於敏感的api接口,需使用https協議web
https是在http超文本傳輸協議加入SSL層,它在網絡間通訊是加密的,因此須要加密證書。
https協議須要ca證書,通常須要交費。redis
原理:用戶登陸後向服務器提供用戶認證信息(如帳戶和密碼),服務器認證完後給客戶端返回一個Token令牌,用戶再次獲取信息時,帶上此令牌,若是令牌正取,則返回數據。對於獲取Token信息後,訪問用戶相關接口,客戶端請求的url須要帶上以下參數:算法
而後將全部用戶請求的參數按照字母排序(包括timestamp,token),而後根據MD5加密(能夠加點鹽),所有大寫,生成sign簽名,這就是所說的url簽名算法。而後登錄後每次調用用戶信息時,帶上sign,timestamp,token參數。後端
例如:原請求https://www.andy.cn/api/user/update/info.shtml?city=北京
(post和get都同樣,對全部參數排序加密)api
加上時間戳和token緩存
https://www.andy.cn/api/user/update/info.shtml?city=北京×tamp=12445323134&token=wefkfjdskfjewfjkjfdfnc
而後更具url參數生成sign,最終的https://www.andy.cn/api/user/update/info.shtml?city=北京×tamp=12445323134&token=wefkfjdskfjewfjkjfdfnc&sign=FDK2434JKJFD334FDF2
的原理是減少明文的暴露次數;保證數據安全的訪問。安全
具體實現以下:服務器
1.api請求客戶端想服務器端一次發送用用戶認證信息(用戶名和密碼),服務器端請求到改請求後,驗證用戶信息是否正確。
若是正確:則返回一個惟一不重複的字符串(通常爲UUID),而後在Redis(任意緩存服務器)中維護Token—-Uid的用戶信息關係,以便其餘api對token的校驗。若是錯誤:則返回錯誤碼。微信
2.服務器設計一個url請求攔截規則
3.Token和Uid關係維護
對於用戶登陸咱們須要建立token–uid的關係,用戶退出時須要需刪除token–uid的關係
獲取所有請求參數
String sign = request.getParameter("sign"); Enumeration<?> pNames = request.getParameterNames(); Map<String, Object> params = new HashMap<String, Object>(); while (pNames.hasMoreElements()) { String pName = (String) pNames.nextElement(); if("sign".equals(pName))continue; Object pValue = request.getParameter(pName); params.put(pName, pValue); }
生成簽名
public static String createSign(Map<String, String> params, boolean encode) throws UnsupportedEncodingException { Set<String> keysSet = params.keySet(); Object[] keys = keysSet.toArray(); Arrays.sort(keys); StringBuffer temp = new StringBuffer(); boolean first = true; for (Object key : keys) { if (first) { first = false; } else { temp.append("&"); } temp.append(key).append("="); Object value = params.get(key); String valueString = ""; if (null != value) { valueString = String.valueOf(value); } if (encode) { temp.append(URLEncoder.encode(valueString, "UTF-8")); } else { temp.append(valueString); } } return MD5Utils.getMD5(temp.toString()).toUpperCase(); }