• 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"}
     


  • 相关阅读:
    HashMap 常问的 9 个问题
    P1855 榨取kkksc03
    Codeforces Round #697 (Div. 3) A. Odd Divisor
    P1474 [USACO2.3]Money System / [USACO07OCT]Cow Cash G
    Codeforces Round #704 (Div. 2) D. Genius's Gambit
    P2800 又上锁妖塔
    P2066 机器分配
    P3399 丝绸之路
    P1351 [NOIP2014 提高组] 联合权值
    P4290 [HAOI2008]玩具取名
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/6351451.html
Copyright © 2020-2023  润新知