我正在构建iOS客户端和django后端服务。系统之间的连接是OAUTH2,由django-oauth2-toolkit实现。
虽然在curl中完成以下命令(返回访问令牌):
curl -X POST -d "grant_type=password&username=<user>&password=<password>" http://<clientID>:<clientSecret>@localhost:8000/o/token/
以下使用Alamofire的Swift代码段会收到&#34; invalid_client&#34;作为回复。
let request = "http://\(Authentication.clientId):\(Authentication.clientSecret)@localhost:8000/o/token/"
var URLRequest = NSMutableURLRequest(URL: NSURL(string: request)!)
URLRequest.HTTPMethod = "POST"
let parameters = ["grant_type": "password", "username": in_username.text!, "password": in_password.text!]
let encoding = Alamofire.ParameterEncoding.URL
(URLRequest, _) = encoding.encode(URLRequest, parameters: parameters)
URLRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
Alamofire.request(URLRequest)
.responseJSON { response in
let data = response
print(data)
}
然后我跟踪了django-oauth2-toolkit源代码中的InvalidClientError
,发现在以下文件的突出显示的片段中引发了异常:
oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
if self.request_validator.client_authentication_required(request):
log.debug('Authenticating client, %r.', request)
print(request) # I included this print message to inspect the request variable in console.
if not self.request_validator.authenticate_client(request):
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request) # RAISED!
我添加了print(request)
行来检查curl和Alamofire提出的请求之间的差异。主要区别在于卷曲版本包含授权密钥:
'Authorization': 'Basic Z3ZFSjVXejloUGgybUJmdDNRaGhXZnlhNHpETG5KY3V6djJldWMwcjpSbVNPMkpwRFQ4bHp1UVFDYXN3T3dvVFkzRTBia01YWWxHVHNMcG5JUGZCUHFjbHJSZE5EOXQzd3RCS2xwR09MNWs1bEE4S2hmRUkydEhvWmx3ZVRKZkFXUDM4OERZa1NTZ0RvS0p3WjUyejRSQ29WRkZBS01RS1lydEpsTWNXag=='
并且Alamofire请求没有。
我非常怀疑这是罪魁祸首,但我从现在开始并不知道该做什么。我真的很感激任何智慧。
答案 0 :(得分:1)
找到了答案!
正在阅读关于HTTP协议的RFC文档,这部分引起了我的注意。
https://tools.ietf.org/html/rfc1945#section-11.1
具体地,
要获得授权,客户端会发送用户ID和密码, 在base64 [5]内用单个冒号(“:”)字符分隔 凭证中的编码字符串。
似乎Alamofire没有像预期的那样以64位编码clientId和clientSecret。显然,curl会自动执行此操作。所以我做了以下事情:
首先编码:
static let clientData: NSData = "\(clientId):\(clientSecret)".dataUsingEncoding(NSUTF8StringEncoding)!
static let client64String = clientData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.init(rawValue: 0))
然后使用结果值设置请求标头:
let request = "http://localhost:8000/o/token/"
var URLRequest = NSMutableURLRequest(URL: NSURL(string: request)!)
URLRequest.HTTPMethod = "POST"
let parameters = ["grant_type": "password",
"username": in_username.text!,
"password": in_password.text!,
]
let encoding = Alamofire.ParameterEncoding.URL
(URLRequest, _) = encoding.encode(URLRequest, parameters: parameters)
// SOLUTION!
URLRequest.setValue("Basic \(Authentication.client64String)", forHTTPHeaderField: "Authorization")
Alamofire.request(URLRequest)
.responseJSON { response in
let data = response
print(data)
}
然后我收到了预期的令牌作为回复。