如何在swift中通过授权访问华为API网关



根据华为API网关应用程序认证文档,我正在尝试通过应用程序认证访问API,标准化请求内容,然后签署请求。作为客户端,我必须遵循与API网关相同的请求规范,这样每个HTTP请求都可以从前端和后端获得相同的签名结果,以完成身份验证。

我用下面的课来完成它。然而,文档确实很难理解。返回错误Incorrect app authentication information: Authorization format is incorrectAPIG.0303

我无法完成这个过程,如果你能提供任何样本来完成这项工作,我真的很感激。

import Foundation
import CommonCrypto
public class SimpleHMACAuth {

/// APP key to authenticate with
public var appKey: String?

/// Secret key to authenticate with
public var secret: String?

/// Algorithm to generate HMAC hash with
public var algorithm: HMACAlgorithm = .sha256

public enum HMACAlgorithm: String {
case sha256 = "sha256"
case sha512 = "sha512"
}

enum RequestSigningError: Error {
case missingAPPKey
case missingSecret
case invalidAlgorithm
case invalidURL
}

fileprivate let dateFormatter: DateFormatter

/// Instantiate with an APP key and secret
/// - Parameters:
///   - appKey: APP key
///   - secret: Secret key
public convenience init(appKey: String, secret: String) {
self.init()

self.appKey = appKey
self.secret = secret
}

/// Instantiate
public init() {
self.dateFormatter = DateFormatter()
self.dateFormatter.dateFormat = "dd MMM yyyy HH:mm:ss zzz"
}

/// Returns a signed version of an input request
/// - Parameter request: Request to sign
/// - Throws: If the request, APP key, secret, or algorithm are invalid
/// - Returns: Signed version of the request
public func sign(_ request: URLRequest) throws -> URLRequest {

guard let signedRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest else {
throw RequestSigningError.invalidURL
}

guard let appKey = self.appKey else {
throw RequestSigningError.missingAPPKey
}

guard let secret = self.secret else {
throw RequestSigningError.missingSecret
}

// Add the "Authorization" header

signedRequest.addValue("APP key (appKey)", forHTTPHeaderField: "Authorization")

// Confirm the "Date" header exists, and add it if not

if signedRequest.value(forHTTPHeaderField: "Date") == nil {

signedRequest.addValue(self.dateFormatter.string(from: Date()), forHTTPHeaderField: "X-Sdk-Date")
}

// If this request has a body but does not yet have the "Content-Length" header, calculate and append it

if let data = signedRequest.httpBody, signedRequest.value(forHTTPHeaderField: "Content-Length") == nil {

signedRequest.addValue("(data.count)", forHTTPHeaderField: "Content-Length")
}

// Canonicalize the request

let canonicalized = try self.canonicalize(signedRequest as URLRequest)

// Generate a signature from the canonicalized representation of the request

let signature = try self.signature(canonicalized: canonicalized, secret: secret, algorithm: algorithm);

// Append the "Signature" header

signedRequest.addValue("SDK-HMAC-SHA256", forHTTPHeaderField: "Authorization")
signedRequest.addValue(appKey, forHTTPHeaderField: "Access")
signedRequest.addValue("SDK-HMAC-SHA256 (signature)", forHTTPHeaderField: "Signature")

return signedRequest as URLRequest
}

/// Generate a string for a request
/// - Parameter request: Request to sign
/// - Throws: Throws if request is invalid
/// - Returns: Signed request
internal func canonicalize(_ request: URLRequest) throws -> String {

guard let url = request.url else {
throw RequestSigningError.invalidURL
}

let method = (request.httpMethod ?? "GET").uppercased()
var path = url.path
let queryString = url.query != nil ? "?(url.query!)" : ""
let allHeaders = request.allHTTPHeaderFields ?? [String : String]()
let data = request.httpBody ?? Data()

if let component = URLComponents(string: url.absoluteString) {
path = component.path
}

// Only sign these headers

let allowedHeaders = [
"authorization",
"date",
"content-length",
"content-type"
]

// Create a new list of headers, with the keys all lower case

var headers = [String: String]();

for (key, value) in allHeaders {

let lowerCaseKey = key.lowercased()

if allowedHeaders.contains(lowerCaseKey) == false {
continue
}

if lowerCaseKey == "content-length" && value == "0" {
continue
}

headers[lowerCaseKey] = value;
}

// Sort the header keys alphabetically

let headerKeys = headers.keys.sorted()

// Create a string of all headers, arranged alphabetically, seperated by newlines

var headerString = ""

for (index, key) in headerKeys.enumerated() {

guard let value = headers[key] else {
continue
}

headerString += "(key):(value)"

if index != headerKeys.count - 1 {
headerString += "n"
}
}

// Hash the data payload

var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
data.withUnsafeBytes { bytes in
_ = CC_SHA256(bytes.baseAddress, CC_LONG(data.count), &digest)
}

let dataHash = Data(digest).map { String(format: "%02hhx", $0) }.joined()

// Combine all components of this request into a string

let components: [String] = [method, path, queryString, headerString, dataHash]

return components.joined(separator: "n");
}

/// Generate a HMAC hash for a canonicalized request
/// - Parameters:
///   - canonicalized: canonicalized version of a request
///   - secret: Secret key
///   - algorithm: Algorithm to use to generate the hmac
/// - Throws: If algorithm is not supported
/// - Returns: Signature for the request
internal func signature(canonicalized: String, secret: String, algorithm: HMACAlgorithm) throws -> String {

let supportedAlgorithms = ["sha1":   (kCCHmacAlgSHA1,   CC_SHA1_DIGEST_LENGTH),
"sha256": (kCCHmacAlgSHA256, CC_SHA256_DIGEST_LENGTH),
"sha512": (kCCHmacAlgSHA512, CC_SHA512_DIGEST_LENGTH)]

guard let (algorithmKey, digestLength) = supportedAlgorithms[algorithm.rawValue] else {
throw RequestSigningError.invalidAlgorithm
}

var digest = [UInt8](repeating: 0, count: Int(digestLength))

CCHmac(CCHmacAlgorithm(algorithmKey), secret, secret.count, canonicalized, canonicalized.count, &digest)

let data = Data(digest)

return data.map { String(format: "%02hhx", $0) }.joined()
}
}

错误代码APIG.303适用于:不正确的应用程序身份验证信息,通常是不正确的程序身份验证。在您的情况下,可能是授权格式不正确

请检查请求方法、路径、查询字符串、请求正文是否与签名时使用的一致;检查客户的日期和时间是否正确;并通过参考Calling API Through App Authentication来检查签名代码是否正确。

以下是详细的API网关用户指南,供您参考:https://support.huaweicloud.com/intl/en-us/ae-ad-1-usermanual-apig/ae-APIG-usermanual.pdf

以下是签名验证的两个例子,看看它们是否能给你一些关于错误发生原因的想法:

private static finà Pattern authorizationPattern = Pattern.compile("SDK-HMAC-SHA256\s+Access=([^,]+),
s?SignedHeaders=([^,]+),\s?Signature=(\w+)");
...
String authorization = request.getHeader("Authorization");
if (authorization == null || authorization.length() == 0) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization not found.");
return;
}
Matcher m = authorizationPattern.matcher(authorization);
if (Ȃmȇfin()) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization format incorrect.");
return;
}
String signingKey = m.group(1);
String signingSecret = secrets.get(signingKey);
if (signingSecret == null) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Signing key not found.");
return;
}
String[] signedHeaders = m.group(2).split(";")
;

另一个:

if "authorization" not in request.headers:
return 'Authorization not found.', 401
authorization = request.headers['authorization']
m = authorizationPattern.match(authorization)
if m is None:
return 'Authorization format incorrect.', 401
signingKey = m.group(1)
signedHeaders = m.group(2).split(";")if "authorization" not in request.headers:
return 'Authorization not found.', 401
authorization = request.headers['authorization']
m = authorizationPattern.match(authorization)
if m is None:
return 'Authorization format incorrect.', 401
signingKey = m.group(1)
signedHeaders = m.group(2).split(";")

相关内容

  • 没有找到相关文章

最新更新