• 最安全的api接口认证


    最安全的api接口认证

    实现步骤:

    1、客户端与服务器都存放着用于验证的Token字段,客户端在本地把自己的 用户名+时间戳+Token 组合进行MD5加密后生成一段新的md5-token。

    2、客户端访问的时候携带:用户名、时间戳、md5-token。

    3、服务端收到请求后,先判断用户名、时间戳是否合法、假设先判断发送过来的时间戳和现在的时间戳不能大于2分钟。

    4、如果是在2分钟之内,到redis里查看有没有该用户为key对应的md5-token,并判断它和发送过来的md5-token是否相同,如果有相同,说明该md5-token已经请求过,不能在操作,如果没找到相同的md5-token,说明是第一次请求,把用户名为key,md5-token为vallue存入redis,存在时间设为2分钟。

    5、如果以上都通过了,在去数据库取出用户名和Token字段像客户端一样的方式进行加密。对比两个加密字段,相同则通过验证。

    1、例如我们在请求的url后带上 用户名+时间戳+加密的Token

    客户端

    复制代码
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import os
    BaseDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    Params = {
        "server": "127.0.0.1",
        "port":8000,
        'request_timeout':30,
        "urls":{
              "asset_report_no_id":"/asset/asset_report_no_id/",
              "asset_report":"/asset/asset_report/",
            },
        'asset_id_path':'%s/var/.asset_id' % BaseDir,
        'log_file': '%s/logs/run_log' % BaseDir,
        'auth':{
            'user':'123456789@qq.com',
            'token': 'abc'
            },
    }
    复制代码
    url=http://127.0.0.1:8000/asset/
    复制代码
    import hashlib,time
    def get_token(username,token_id):
        timestamp = int(time.time())
        md5_format_str = "%s
    %s
    %s" %(username,timestamp,token_id)
        obj = hashlib.md5()
        obj.update(md5_format_str)
        print "token format:[%s]" % md5_format_str
        print "token :[%s]" % obj.hexdigest()
        return obj.hexdigest()[10:17], timestamp
    复制代码
    复制代码
    def attach_token(url_str):
        '''生成一个加密验证在url后'''
        user = settings.Params['auth']['user']
        token_id = settings.Params['auth']['token']
    
        md5_token,timestamp = get_token(user,token_id)
        url_arg_str = "user=%s&timestamp=%s&token=%s" %(user,timestamp,md5_token)
        if "?" in url_str:
            new_url = url_str + "&" + url_arg_str
        else:
            new_url = url_str + "?" + url_arg_str
        return  new_url
    
    #生成一个带着加密token的url
    url = attach_token(url)
    复制代码

    发送请求

    data_encode = urllib.urlencode(asset_data)#asset_data为要发送的数据
    req = urllib2.Request(url=url,data=data_encode)
    res_data = urllib2.urlopen(req,timeout=settings.Params['request_timeout'])
    callback = res_data.read()
    callback = json.loads(callback)
    print (callback)

    服务端

    2、我们给服务端写一个装饰器token_required,用来验证

    复制代码
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import time,hashlib,json
    from asset import models
    from django.shortcuts import render,HttpResponse
    from cmdb import settings
    from django.core.exceptions import ObjectDoesNotExist
    
    def gen_token(username,timestamp,token):
        token_format = "%s
    %s
    %s" %(username,timestamp,token)
        obj = hashlib.md5()
        obj.update(token_format)
        return obj.hexdigest()[10:17]
    
    
    def token_required(func):
        def wrapper(*args,**kwargs):
            response = {"errors":[]}
            get_args = args[0].GET
            username = get_args.get("user")
            token_md5_from_client = get_args.get("token")
            timestamp = get_args.get("timestamp")
    
            if not username or not timestamp or not token_md5_from_client:
                response['errors'].append({"auth_failed":"This api requires token authentication!"})
                return HttpResponse(json.dumps(response))
            try:
                if abs(time.time() - int(timestamp)) > settings.TOKEN_TIMEOUT:#验证时间有没有超过2分钟
                    response['errors'].append({"auth_failed":"The token is expired!"})
                else:
                    '''如果没超过两分钟,检查redis里有没有这个加密token'''
                    red_result = __redies_token(username,token_md5_from_client)
                    if red_result:  #等于True说明是第一次请求,进入下一步验证
                        user_obj = models.MyUser.objects.get(email=username)
                        token_md5_from_server = gen_token(username,timestamp,user_obj.token)
                        if token_md5_from_client != token_md5_from_server:
                            response['errors'].append({"auth_failed":"Invalid username or token_id"})
                        else:
    
                            print("通过验证")
                    else:
                        response['errors'].append({"auth_failed":"The token is expired!"})
    
                    print("33[41;1m;%s ---client:%s33[0m" %(time.time(),timestamp), time.time() - int(timestamp))
            except ObjectDoesNotExist as e:
                response['errors'].append({"auth_failed":"Invalid username or token_id"})
            if response['errors']:
                return HttpResponse(json.dumps(response))
            else:
                return  func(*args,**kwargs)
        return wrapper
    
    def __redies_token(username,token_md5_from_client):
        import redis
        r = redis.Redis(host='192.168.0.109', port=6379)
        val =  r.get(username)
        if val == token_md5_from_client:
            print("是以请求过的token")
            return False
        else:#不存在,则以用户名为key,加密的token为value存入缓存,存在时间2分钟
            r.set(username, token_md5_from_client,ex=120)
            return True
    复制代码
  • 相关阅读:
    在Pycharm中使用GitHub
    Ubuntu20.04开启root账户的方法步骤
    使用git push文件到gitee
    Dell主机安装win10+Ubuntu20.04双系统
    Golang select 基础语法与用法
    Golang websocket 实现消息推送
    Golang + gRPC 实践
    Golang实现RPC
    unigui+fastReport实现web打印方案(43)
    [控件] 加强版 TOneSelection (改良自 Berlin 10.1 TSelection)
  • 原文地址:https://www.cnblogs.com/ExMan/p/9807154.html
Copyright © 2020-2023  润新知