webapi應用架構詳解


webapi適用場景

常見的應用包括以下四類,PC客戶端程序,APP程序,網站程序,H5程序。
這些應用需要的數據,服務可由同一個接口服務程序提供,這樣,大大提高了產品多平台設計開發的效率,避免了重復的編碼。

什么是webapi

webapi一般采用restful風格。以tornado為例,url路由配置如下:

url = [
    (r'/test', testfc.testHandler)
]

業務邏輯層,返回數據一般為json格式:

class testHandler(RequestHandler):
    def get(self):
        self.post()
    def post(self):
        result={}
        if True:
            result["code"]="200"
            result["status"]="true"
            result["result"]="success"
        else:
            result["code"]="300"
            result["status"]="false"
            result["result"]="fail"
        self.write(json_encode(result))
        return

webapi訪問方式如下:

http://127.0.0.1:9999/test

返回結果:
{"status": "true", "code": "200", "result": "success"}

webapi架構設計

如何確認一個app能夠訪問webapi?
使用AppID驗證app訪問webapi的合法性,AppID為服務端給出的一個ID標志。
我們可以為web/app/winform分別分配一個ID,從而可以確定訪問的合法性,和訪問的渠道。

如何保證app參數的正確性,沒有被篡改?
客戶端使用AppID對應的AppSecert,對參數進行簽名(MD5/SHA等)
服務端使用同樣的方式簽名,和客戶端簽名校驗。

如何防止webapi url被截獲,重新訪問?
客戶端訪問webapi時帶上時間戳參數,服務端對時間戳進行校驗,如10分鍾內的訪問才是有效的。

涉及具體用戶的操作時,如何驗證用戶?
可以使用username,psw參數的方式訪問webapi。但是這種方式很不安全。
使用授權token是很好的解決辦法。在用戶登錄成功時,服務端生成一個授權碼,對應用戶信息。
訪問時帶上token參數,服務端查詢token有效性,和token對應的用戶信息。

使用示例

簽名代碼如下:

#coding:utf-8

__author__ = 'jy'

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
sys.path.append('..')
import datetime
import time
import math
import hashlib
import urllib
def md5encode(source):
    m2 = hashlib.md5()
    m2.update(source)
    return m2.hexdigest()
def dataSort(data):
    dataKeys=data.keys()
    dataKeys.sort()
    result=""
    for key in dataKeys:
        result+=key.strip()
        result+=data[key].strip()
    return result 
def dataSecret(data):
    secret="af4d2c92-4bb7-11e5-8111-00163e001071"
    data=secret+data+secret
    return data 
def getSign(postdata):
    try:
        #升序排列,合並為字符串
        dataSign=dataSort(postdata)
        #加密鑰
        dataSign=dataSecret(dataSign)
        #md5編碼
        dataSign=md5encode(dataSign)
        return dataSign
    except Exception as error:
        pass

驗證url參數代碼如下:

#coding:utf-8
__author__ = 'haoy'

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
sys.path.append('..')
from tornado.escape import json_decode, json_encode
import datetime
import time
import math
from utils.sign import *
def valiUrldata(data):
    result={}
    try:
        #判斷appKey是否合法
        appKey=data.get("appKey","") 
        if appKey!="21ec85ec-30ca-491b-8bfb-c05e479eadc0":
            result["code"]="300"
            result["status"]="false"
            result["result"]="賬號不合法"
            return result
        #appKey對應的secret
        appSecret="af4d2c92-4bb7-11e5-8111-00163e001071"
        #檢驗時間
        timeStamp=data.get("timeStamp","0")
        timeStamp=int(timeStamp)
        nowtime=int(round(time.time()))

        if abs(timeStamp-nowtime)>600:
            result["code"]="300"
            result["status"]="false"
            result["result"]="請求時間戳不合法"
            return result

        #校驗簽名
        clientSign=data.get("sign","")
        if clientSign=="":
            result["code"]="300"
            result["status"]="false"
            result["result"]="請求參數簽名不能為空"
            return result
        data.pop("sign")
        serverSign=getSign(data)
        print serverSign
        if clientSign!=serverSign:
            result["code"]="300"
            result["status"]="false"
            result["result"]="請求參數簽名不合法"
            return result
        result["code"]="200"
        result["status"]="true"
        result["result"]="通過驗證"
        return result
    except Exception as error:
        result["code"]="300"
        result["status"]="false"
        result["result"]="異常:"+error.message
        return result

登錄代碼如下:

import uuid
import redis
class testLoginHandler(BaseHandler):
    def get(self):
        self.post()
    def post(self):
        #獲取url參數
        args=self.request.arguments
        data={}
        for key in args:
            data[key]=self.get_argument(key,"")
        #驗證url參數
        valiResult=valiUrldata(data)
        if valiResult["code"]=="300":
            self.write(json_encode(valiResult).decode("unicode_escape"))
            return
        username=self.get_argument("username","")
        psw=self.get_argument("psw","")
        if username=="shijingjing07" and psw=="123456":
            token = uuid.uuid1()
            redisPool = redis.ConnectionPool(host='127.0.0.1',password='123456', port=6379, db=0)
            cache = redis.Redis(connection_pool=redisPool)
            cache.setex(token,username,300)
            result["code"] = 200
            result["status"] = "true"
            result["result"] = token
        else:
            result["code"] = 300
            result["status"] = "false"
            result["result"] = "account illegal"
        self.write(json_encode(result))

返回結果:

{"status": "true", "code": 200, "result": "5720c334-dbcc-11e6-84f1-00163e001071"}
 



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM