forked from baron/baron-sso
SMS 인증을 위한 Naver SENS 연동 및 API 구현
This commit is contained in:
107
backend/internal/service/sms_service.go
Normal file
107
backend/internal/service/sms_service.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"baron-sso-backend/internal/domain"
|
||||
)
|
||||
|
||||
type SmsServiceImpl struct {
|
||||
accessKey string
|
||||
secretKey string
|
||||
serviceID string
|
||||
senderPhone string
|
||||
}
|
||||
|
||||
func NewSmsService() domain.SmsService {
|
||||
return &SmsServiceImpl{
|
||||
accessKey: os.Getenv("NAVER_CLOUD_ACCESS_KEY"),
|
||||
secretKey: os.Getenv("NAVER_CLOUD_SECRET_KEY"),
|
||||
serviceID: os.Getenv("NAVER_CLOUD_SERVICE_ID"),
|
||||
senderPhone: os.Getenv("NAVER_SENDER_PHONE_NUMBER"),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SmsServiceImpl) SendSms(to, content string) error {
|
||||
timestamp := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)
|
||||
apiURL := fmt.Sprintf("https://sens.apigw.ntruss.com/sms/v2/services/%s/messages", s.serviceID)
|
||||
log.Printf("Requesting SENS API URL: %s", apiURL)
|
||||
|
||||
reqBody := domain.NaverSmsRequest{
|
||||
Type: "SMS",
|
||||
ContentType: "COMM",
|
||||
CountryCode: "82",
|
||||
From: s.senderPhone,
|
||||
Content: content,
|
||||
Messages: []domain.SmsMessage{
|
||||
{
|
||||
To: to,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
jsonBody, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshalling request body: %w", err)
|
||||
}
|
||||
|
||||
signature, err := s.makeSignature("POST", fmt.Sprintf("/sms/v2/services/%s/messages", s.serviceID), timestamp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating signature: %w", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonBody))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating request: %w", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("x-ncp-apigw-timestamp", timestamp)
|
||||
req.Header.Set("x-ncp-iam-access-key", s.accessKey)
|
||||
req.Header.Set("x-ncp-apigw-signature-v2", signature)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error sending request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading response body: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
log.Printf("error response from naver cloud sms api: %s", string(respBody))
|
||||
return fmt.Errorf("error sending sms: status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
log.Printf("sms sent successfully: %s", string(respBody))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SmsServiceImpl) makeSignature(method, url, timestamp string) (string, error) {
|
||||
space := " "
|
||||
newLine := "\n"
|
||||
message := method + space + url + newLine + timestamp + newLine + s.accessKey
|
||||
|
||||
h := hmac.New(sha256.New, []byte(s.secretKey))
|
||||
_, err := h.Write([]byte(message))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
Reference in New Issue
Block a user