大华平台登录过程两次鉴权python demo
客户说按照接口文档死活无法鉴权,自己试了一下
官方文档
第一次鉴权
功能说明
第一次鉴权必然会报401错误,原因是请求入参还没有平台的令牌,这次鉴权的目的是获取到平台的加密领域、随机密钥、加密方式以及平台RSA加密公钥,以便于计算出签名,签名是作为第二次鉴权的入参之一。
接口调用请求说明
http请求方式:POST
请求地址:https://10.35.210.133:443/admin/API/accounts/authorize
请求数据示例
POST /admin/API/accounts/authorize HTTP/1.1
Host: 10.35.210.133
Connection: close
Content-Type: application/json;charset=UTF-8
Content-Length: 70
{
"userName": "system",
"ipAddress": "",
"clientType": "WINPC_V1"
}
请求参数
返回数据示例
{
"realm": "f689ed8c43530d68bf7d6e95a62f7f87",
"randomKey": "8011f60ea78547ee",
"encryptType": "MD5",
"publickey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkCdJdUy6Hd6OQyMDe1dNH8Pb9mRGxKuoLGIQ8xQ6AGYC/TZ+fnC4ton7l/qDcsHrvAGZJQtk7pUOrvQgzHbIsh1qEY5xfQYzP1Sah25NYkT1Vo4Z7vCYPASKjsVerzZrd7kvEX5kA3GBWwTRFE4dw4R33/Nr4TJM916m99sN7Nba1JdyLno7DauBIc4dQp6CbqovyK0hhCHTNoX5WIOj6iElgANW22ukgKYrHVxlJ6SxbyAd9pCNq85yz3QIZ3QsGDI/xHI+zibD3qAlqSsJEAtVBmlyLKf8jT0NKhLfY6lglt3F0YmxvCsVjErtZvduLkuv8i6nbHBfpA5urUa+GQIDAQAB"
}
返回参数
第二次鉴权
功能说明
第二次鉴权请求前需要根据第一次鉴权的返回值计算出签名signature的值
根据用户提供的用户名(userName)、密码(password),第一次鉴权返回的域信息(realm),随机值(randomKey)和加密方式(encryptType,MD5加密),采用如下方式计算出签名(signature) 伪代码示例:
temp = md5(password)
temp = md5(userName + temp)
temp = md5(temp)
temp = md5(userName + ":" + realm + ":" + temp)
signature = md5(temp + ":" + randomKey)
如上述伪代码所示,一共需要进行5次MD5加密,其中参数和结果值均为字符串,md5加密结果值的字母都为小写。 假定值为如下:
各个阶段的计算值如下所示:
最后得到07d3ae5ea480de187c2ca0f77742e3ce就是签名signature的值,它将作为第二次鉴权的入参之一。
注意:第二次鉴权得到token值后,后续要调用平台的其他业务接口都需要把token放在请求头里, 字段名称为X-Subject-Token,没有放令牌或者令牌过期,请求都会返回401。
接口调用请求说明
http请求方式:POST
请求地址:https://10.35.210.133:443/admin/API/accounts/authorize
请求数据示例
POST /admin/API/accounts/authorize HTTP/1.1
Host: 10.35.210.133
Connection: close
Content-Type: application/json;charset=UTF-8
Content-Length: 652
{
"mac": "2C:F0:5D:44:6F:8B|02:00:4C:4F:4F:50",
"signature": "07d3ae5ea480de187c2ca0f77742e3ce",
"userName": "system",
"randomKey": "8011f60ea78547ee",
"publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA156uLLwO6FzulZtt7KxJDV2P2BKNptc++1RLaM09uhPjDfYcwHrG5jvZLfJRbU0lg/rT0XqBdUcYiUfivJID4jINXEAkJ4S9f28cXv9AUJctud/6cY9Hmi1O6LCbaoENhUdKiI57uRG68X8fABcMWODa4Pj/2Zudj6Q7o8osDh5OK8HjG5gO8ZiNHH3M7mzsa8SpUUAza+A9QJxS5fQ5RuKW3IvCjYgdP8Ka2vLOgwBMAradJRl8vAa9l0E0s6wTDJCszK/Kgzb1sXeFryaPoOSyZGvXGeNeYc5+hxJSFkuyK5ILPYo86dDUBGlQIBukKuyzK17cngpFToWb5ELE0QIDAQAB",
"encryptType": "MD5",
"ipAddress": "",
"clientType": "WINPC_V1",
"userType": "0"
}
请求参数
返回数据示例
{
"duration": 30,
"token": "9b3ddf2993e34f15acd7f870784617ad",
"userId": "1",
"versionInfo": {
"lastVersion": "26007",
"updateUrl": "/client/x86/General_DAEDSS-MobileCenter_Client-x86_V2.001.0000001.0.R.20210819.exe;/client/x64/General_DAEDSS-MobileCenter_Client-x64_V2.001.0000001.0.R.20210819.exe"
},
"tokenRate": 1800,
"secretKey": "h76Ori5QieFD0ijbKIiC4zNj+3d6JOAjIotCO/Uq51HXi+Z2oFaIhFbwHYjKjZYNhhB4cH6OHsChKziksrD3kyhw5mCzl2ZkrH8qY/DC+u1k69mdTkq2Zj/CKhYgoSpRedltIMI/ZTfumqTHT3vIwgJEzijhacETycqydMyVdqTSv6dDLI4kd5CHM51mc9zGE8zcQp2Tm53z6yLQgVTFHn21bYJWMaGynKuH036m69kQMUaPu4tOAt/VzjZTq+H/rHyoRlCcVSKaun/i08CZvXyPUDr0zdsq0Y3Ar5fqbvTEOmv5Fqwp3EbDZKGiSA/UlHkrtopbLeB38Am/b6pCZg==",
"secretVector": "hMqJus90nrYI1LKdujTa387LEl0s61DvD0zdmTpoQvHKyE463ThqFnWiAJ2TCpIQCGsAuhXsl7Zcqfd+1hqumgZU6phhfR0VGnYow+m2PR9MX2Rj4ZvSpCwQy/sDy5VaxhyCWnYFMFKLeP6rOOhoSQoxVaMKGF9FywHCCqSRr1HgImSNDKOaUdGwq1IEe1sLfW0/DOUNfA3ZK//9mozlZ0plAxR5YTbQ0Z6NEg/5vGz7oyaj7Ajb+X8ax+762szmNA696kCoHGGTRe8NGxyzCKhgkZ8FOKiGoyWR7sBuY2ZYKekCVVMqbdsUB39rBtqAerxiSOA0Tr1vu3CuRTVE+A==",
"reused": "1"
}
返回参数
demo
import requests import json import hashlib ip="https://平台ip:端口/" username="平台用户名" passwd="平台密码" import types def getmd5(data): m = hashlib.md5() m.update(data.encode()) return m.hexdigest() def first(): data1={ "userName":username, "ipAddress":"", #无所谓 "clientType":"WINPC_V1" #无所谓 } headers={ 'Server': 'openresty', 'Date': 'Fri, 01 Jul 2022 09:30:41 GMT', 'Content-Type': 'text/html;charset=UTF-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Set-Cookie': 'JSESSIONID=D05889B64730C3DEFDEE627D115DB4D9; Path=/admin; Secure; HttpOnly', 'X-Frame-Options': 'SAMEORIGIN', 'Pragma':'no-cache', 'Cache-Control': 'no-cache', 'Expires': 'Thu, 01 Dec 1994 16:00:00 GMT', 'Content-Language': 'zh-CN' } print(data1) r=json.loads(requests.post(ip+"admin/API/accounts/authorize",json=data1,verify=False).text) #没有证书,又要使用https,因此所有请求需要加入verify=False return r['realm'],r['randomKey'],r['encryptType'],r['publickey'] def second(signature,realm,randomKey,encryptType,publickey): data={ "mac":"2C:F0:5D:44:6F:8B|02:00:4C:4F:4F:50", #无所谓 "signature":signature, "userName": username, "randomKey":randomKey, "publicKey":publickey, "encryptType": encryptType, "ipAddress": "", "clientType": "WINPC_V1", #无所谓 "userType": "0" } r=json.loads(requests.post(ip+"admin/API/accounts/authorize",json=data,verify=False).text) return r['duration'],r['token'],r['userId'],r['versionInfo'],r['secretKey'],r['secretVector'] def getgps(token): headers={ "X-Subject-Token":token } data={ "capTimeStrStart": "2022-07-01 00:00:00", "capTimeStrEnd": "2022-09-15 23:59:59", "plateNo": "浙E000000", "page": 1, "pageSize": 20 } r=json.loads(requests.post(ip+"/vehicleServer/api/getGpsDetailInfo?nowTime=1631711885503",json=data,headers=headers,verify=False).text) return r realm,randomKey,encryptType,publickey=first() print(realm,randomKey,encryptType,publickey) temp = getmd5(passwd) temp = getmd5(username + temp) temp = getmd5(temp) temp = getmd5(username + ":" + realm + ":" + temp) signature = getmd5(temp + ":" + randomKey) print("\n\n") print(signature) duration,token,userId,versionInfo,secretKey,secretVector=second(signature,realm,randomKey,encryptType,publickey) print(duration,token,userId,versionInfo,secretKey,secretVector) print("轨迹:"+str(getgps(token)))
first函数进行第一次鉴权并获得 realm,randomKey,encryptType,publickey,进而计算出signature,并由second函数二次鉴权后获得token,最后getgps调用了一个GPS轨迹获取接口检测权限有效性