문자인증을 통한 로그인 회원가입 기능을 구현하기위해 네이버 SMS API를 사용해서 구현하였습니다.
final class SMSAuthService {
enum SMSRequestType: String {
case sms
case lms
case mms
var name: String {
return self.rawValue.uppercased()
}
}
struct SMSRequest: Codable {
let type: String // (SMS | LMS | MMS)
/// 발신번호
let from: String
/// 기본 메시지 제목
let subject: String?
/// 기본 메시지 내용
let content: String
/// 메시지 정보
let messages: [Message]
let files: [File]
}
struct Message: Codable {
/// 수신번호
let to: String
}
struct File: Codable {
let fileId: String?
}
}
필요한 정보들을 Key 값을 Plist 파일로 따로 뺴서 Git에 팀원의 전화번호가 올라가는 불상사를 막았습니다. 그 후 번들파일을 extension 하여 메서드를 만들어서 사용하였습니다.
extension Bundle {
var senderPhoneNumber: String {
guard let file = self.path(forResource: "APIKeys", ofType: "plist") else { return "" }
guard let resource = NSDictionary(contentsOfFile: file) else { return "" }
guard let key = resource["SENDERPHONENUMBER"] as? String else {
fatalError("KEY를 찾을수없음")
}
return key
}
var accessKey: String {
guard let file = self.path(forResource: "APIKeys", ofType: "plist") else { return "" }
guard let resource = NSDictionary(contentsOfFile: file) else { return "" }
guard let key = resource["ACCESS_KEY"] as? String else {
fatalError("KEY를 찾을수없음")
}
return key
}
var secretKey: String {
guard let file = self.path(forResource: "APIKeys", ofType: "plist") else { return "" }
guard let resource = NSDictionary(contentsOfFile: file) else { return "" }
guard let key = resource["SECRET_KEY"] as? String else {
fatalError("KEY를 찾을수없음")
}
return key
}
var serviceId: String {
guard let file = self.path(forResource: "APIKeys", ofType: "plist") else { return "" }
guard let resource = NSDictionary(contentsOfFile: file) else { return "" }
guard let key = resource["SERVICE_ID"] as? String else {
fatalError("KEY를 찾을수없음")
}
return key
}
}
우선 밑의 사진처럼 API Header에서 요구하는것들을 전부 만들겁니다.
private let timestamp = String(Int(Date().timeIntervalSince1970 * 1000))
import CommonCrypto
private func makeSignature() -> String {
let url = "/sms/v2/services/\(serviceId)/messages"
let message = method + " " + url + "\n" + timestamp + "\n" + accessKey
let keyData = secretKey.data(using: .utf8)!
var macOut = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
keyData.withUnsafeBytes { keyBytes in
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), keyBytes.baseAddress, keyData.count, message, message.utf8.count, &macOut)
}
let hmacData = Data(bytes: macOut, count: Int(CC_SHA256_DIGEST_LENGTH))
let base64Encoded = hmacData.base64EncodedString()
return base64Encoded
}
이제 API에 requset를 하기 위한 JSON의 BODY 부분들의 데이터들을 정의합니다.
private let accessKey = Bundle.main.accessKey
private let secretKey = Bundle.main.secretKey
private let serviceId = Bundle.main.serviceId
private let senderPhoneNumber = Bundle.main.senderPhoneNumber
private let receiverPhoneNumber = " "
private var randomNumber = ""
private let method = "POST"
private let timestamp = String(Int(Date().timeIntervalSince1970 * 1000))
func configRandomCode() -> String {
let digits = "0123456789"
var randomCode = ""
for _ in 0..<6 {
let randomIndex = Int.random(in: 0..<digits.count)
let digit = digits[digits.index(digits.startIndex, offsetBy: randomIndex)]
randomCode.append(digit)
}
print("인증번호 생성: \\(randomCode)")
randomNumber = randomCode
return randomCode
}
func checkRightCode(code: String) -> Bool {
if randomNumber == code {
return true
} else {
return false
}
}
참고
네이버
https://losskatsu.github.io/blockchain/sha256/#4-sha-256-%EA%B3%BC%EC%A0%95