Notice
Recent Posts
Recent Comments
Link
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
관리 메뉴

개발자 되버리기

Springboot + NAVER S.E.N.S 보내기 (V2 헤더 세팅) 본문

개발/Spring_Boot

Springboot + NAVER S.E.N.S 보내기 (V2 헤더 세팅)

구본익 2020. 11. 14. 14:48

사내에서 문자 서비스를 구축해야해서 네이버 nens를 다루게 되었는데 제가 미숙한 탓에 헤더 세팅하는데 어려움이 있었습니다.

(혼자 핑계로 네이버 API 헤더 세팅 어렵다고.. 꿍시렁)

 

부디 이 글 보시고 헤더 세팅하시는데 어려움을 덜어내셨으면 좋겠습니다.

 

헤더를 이렇게 저렇게 세팅하라는 네이버 플랫폼..

 

네이버 플랫폼에서 제공하는 헤더 만드는 예시

 

 

저는 막상 저 예제만 보고는 잘 모르겠더라고요... 

결론은 헤더의 내용을 암호화하여 다시 헤더에 넣어라! 이런 얘기더랍니다...

 

소스코드 부터 확인해보겠습니다.

public String makeSignature(Long time) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException {
        String space = " ";					// one space
        String newLine = "\n";					// new line
        String method = "POST";					// method
        String url = "/sms/v2/services/"+applicationNaverSENS.getServiceid()+"/messages";	// url (include query string)
        String timestamp = time.toString();			// current timestamp (epoch)
        String accessKey = applicationNaverSENS.getAccesskey();			// access key id (from portal or Sub Account)
        String secretKey = applicationNaverSENS.getSecretkey();

        String message = new StringBuilder()
                .append(method)
                .append(space)
                .append(url)
                .append(newLine)
                .append(timestamp)
                .append(newLine)
                .append(accessKey)
                .toString();

        SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(signingKey);

        byte[] rawHmac = mac.doFinal(message.getBytes("UTF-8"));
        String encodeBase64String = Base64.encodeBase64String(rawHmac);

        return encodeBase64String;
    }

저는 SMS를 위주로 코딩을 하였습니다.

네이버 플랫폼에서 제시하는 예제랑 조금 다르다면 저는 time값을 인자로 받아서 헤더를 만듭니다.

이 이유는 글 후반부에 말씀드리겠습니다. 

 

보시다시피 accessKey 와 secretKey는 yml파일에서 따로 읽어오셔도 됩니다. (각자의 방식으로 불러오시면 됩니다.)

 

 

일단 네이버 SMS 요청 API URL은 https://sens.apigw.ntruss.com 입니다.

URI 는 /sms/v2/services/{자신의 serviceID}/messages 입니다.

 

서비스 아이디는 

 

자신의 네이버 플랫폼 콘솔로 이동하신 후 위 사진처럼 프로젝트에서 맨 오른쪽에 '서비스ID'에서 확인하실 수 있습니다.

 

일반메시지를 보내는 예시로 코딩을 해보도록 하겠습니다.

우선은 일반 메시지에서 'messages' json 부분을 구성해줄 클래스를 생성합니다.

 

해당 게시글에서는 json을 만들기 위해 ObjectMapper 클래스를 사용하였습니다!

 

 

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Service;

@Data
@Service
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MessagesRequestDto {
    private String to;
    private String content;
}

 

 

이후에는 전체적인 body를 만들어줄 json 클래스를 만듭니다.

@Data
@Service
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class SmsRequestDto {
    private String type;
    private String contentType;
    private String countryCode;
    private String from;
    private String content;
    private List<MessagesRequestDto> messages;
}

 

 

이후에 헤더와 바디를 조합해 restTemplate로 post 요청을 보냅니다.

 

 

이후에는 데이터를 받아줄 Dto도 필요합니다.

 

@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class SendSmsResponseDto {
    private String statusCode;
    private String statusName;
    private String requestId;
    private Timestamp requestTime;
}

 

밑에는 전체 코드 입니다.

@Getter
@Setter
@AllArgsConstructor
@Component
public class SmsService {

    private final ApplicationNaverSENS applicationNaverSENS;
    
    public SendSmsResponseDto sendSms(String recipientPhoneNumber, String content) throws ParseException, JsonProcessingException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, URISyntaxException {
        Long time = new DateCreator().getTimestamp().getTime();
        List<MessagesRequestDto> messages = new ArrayList<>();
        // 보내는 사람에게 내용을 보냄.
        messages.add(new MessagesRequestDto(recipientPhoneNumber,content)); // content부분이 내용임

        // 전체 json에 대해 메시지를 만든다.
        SmsRequestDto smsRequestDto = new SmsRequestDto("SMS", "COMM", "82", applicationNaverSENS.getSendfrom(), "MangoLtd", messages);

        // 쌓아온 바디를 json 형태로 변환시켜준다.
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonBody = objectMapper.writeValueAsString(smsRequestDto);

        // 헤더에서 여러 설정값들을 잡아준다.
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("x-ncp-apigw-timestamp", time.toString());
        headers.set("x-ncp-iam-access-key", applicationNaverSENS.getAccesskey());

        // 제일 중요한 signature 서명하기.
        String sig = makeSignature(time);
        System.out.println("sig -> " + sig);
        headers.set("x-ncp-apigw-signature-v2", sig);

        // 위에서 조립한 jsonBody와 헤더를 조립한다.
        HttpEntity<String> body = new HttpEntity<>(jsonBody, headers);
        System.out.println(body.getBody());

        // restTemplate로 post 요청을 보낸다. 별 일 없으면 202 코드 반환된다.
        RestTemplate restTemplate = new RestTemplate();
        SendSmsResponseDto sendSmsResponseDto = restTemplate.postForObject(new URI("https://sens.apigw.ntruss.com/sms/v2/services/"+applicationNaverSENS.getServiceid()+"/messages"), body, SendSmsResponseDto.class);
        System.out.println(sendSmsResponseDto.getStatusCode());
        return sendSmsResponseDto;
    }

    public String makeSignature(Long time) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException {
        String space = " ";					// one space
        String newLine = "\n";					// new line
        String method = "POST";					// method
        String url = "/sms/v2/services/"+applicationNaverSENS.getServiceid()+"/messages";	// url (include query string)
        String timestamp = time.toString();			// current timestamp (epoch)
        String accessKey = applicationNaverSENS.getAccesskey();			// access key id (from portal or Sub Account)
        String secretKey = applicationNaverSENS.getSecretkey();

        String message = new StringBuilder()
                .append(method)
                .append(space)
                .append(url)
                .append(newLine)
                .append(timestamp)
                .append(newLine)
                .append(accessKey)
                .toString();

        SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(signingKey);

        byte[] rawHmac = mac.doFinal(message.getBytes("UTF-8"));
        String encodeBase64String = Base64.encodeBase64String(rawHmac);

        return encodeBase64String;
    }
}

 

테스트코드로 실행시켜봅니다.

 

@SpringBootTest
class ApplicationTests {
    @Autowired
    private SmsService smsService;

    @Test
    void sendSms() throws JsonProcessingException, ParseException, UnsupportedEncodingException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException {
        smsService.sendSms("01012345678","문자 보내는거 너무 쉬워요!");
    }
}

 

 

실제로 문자가 잘 오는 것을 확인하실 수 있습니다.

Comments