[naver] 네이버웍스 API 2.0 토큰인증 : 메시지발송 예제
2023. 12. 22. 14:21ㆍnaver
token jwt 계정 인증
네이버웍스 2.0 API를 사용하기 위해서는 인증먼저 해야한다. 인증 방법에는 Oauth방식과 JWT 방식이 있다.
Spring 기반의 예제를 작성해보도록 하겠다.
1. Developer Console 사이트접속후 각종 인증키 확보
- Client ID
- Client Secret
- Service Account
- Private Key
2. 스프링 pom.xml
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.0</version>
</dependency>
3. RSAUtils.java
rsa를 사용해야 하기때문에 Util파일로 하나 생성한다.
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.FileCopyUtils;
public class RSAUtils {
public static String getKey(String filename) throws IOException{
ClassPathResource resource = new ClassPathResource(filename);
InputStream inputStream = resource.getInputStream();
byte[] bdata = FileCopyUtils.copyToByteArray(inputStream);
String data = new String(bdata, StandardCharsets.UTF_8);
return data;
}
public static RSAPrivateKey getPrivateKey(String filename) throws IOException, GeneralSecurityException{
String privateKeyPEM = getKey(filename).trim();
return getPrivateKeyFromString(privateKeyPEM);
}
public static RSAPrivateKey getPrivateKeyFromString(String key) throws IOException, GeneralSecurityException{
String privateKeyPEM = key;
privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----", "");
privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.decodeBase64(privateKeyPEM);
KeyFactory kf = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(keySpec);
return privKey;
}
public static RSAPublicKey getPublicKey(String filename) throws IOException, GeneralSecurityException{
String publicKeyPEM = getKey(filename);
return getPublicKeyFromString(publicKeyPEM);
}
public static RSAPublicKey getPublicKeyFromString(String key) throws IOException, GeneralSecurityException{
String publicKeyPEM = key;
publicKeyPEM = publicKeyPEM.replace("-----BEGIN PRIVATE KEY-----", "");
publicKeyPEM = publicKeyPEM.replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.decodeBase64(publicKeyPEM);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
return pubKey;
}
public static String sign(PrivateKey privateKey, String message) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException{
Signature sign = Signature.getInstance("SHA1withRSA");
sign.initSign(privateKey);
sign.update(message.getBytes("UTF-8"));
return new String(Base64.encodeBase64(sign.sign()), "UTF-8");
}
public static String encrypt(String rawText, PublicKey publicKey) throws IOException, GeneralSecurityException{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.encodeBase64String(cipher.doFinal(rawText.getBytes("UTF-8")));
}
public static String decrypt(String cipherText, PrivateKey privateKey) throws IOException, GeneralSecurityException{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(Base64.decodeBase64(cipherText)), "UTF-8");
}
}
4. TokenTest.java
위에서 확인하였던 Client ID / Client Secret / Service Account / Private Key 정보를 아래에 입력한다. Private Key 파일 위치는 통상 spring경로인 src > main > resources 아래에 두게되면 아래처럼 작성하면 된다.
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.naverworks.message.util.RSAUtils;
public static void main(String[] args) throws Exception{
Map<String, Object> headers = new HashMap<String, Object>();
headers.put("alg", "RS256");
headers.put("typ", "JWT");
Date iat = new Date();
Date exp = DateUtils.addMinutes(new Date(), 30);
String grantType = URLEncoder.encode("urn:ietf:params:oauth:grant-type:jwt-bearer", StandardCharsets.UTF_8.toString());
RSAPublicKey publicKey = null;
RSAPrivateKey privateKey = RSAUtils.getPrivateKey("private.key");
Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey);
String assertion = JWT.create().withHeader(headers)
.withIssuer("") //Client ID
.withSubject("") //Service Account
.withIssuedAt(iat)
.withExpiresAt(exp)
.sign(algorithmRS);
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("grant_type", grantType));
params.add(new BasicNameValuePair("client_id", "")); //Client ID
params.add(new BasicNameValuePair("client_secret", "")); //Client Secret
params.add(new BasicNameValuePair("assertion", assertion));
params.add(new BasicNameValuePair("scope", "bot"));
URI uri = new URI("https://auth.worksmobile.com/oauth2/v2.0/token");
URIBuilder ub = new URIBuilder(uri);
String contentType = "application/x-www-form-urlencoded";
HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost http = new HttpPost(ub.toString());
http.addHeader("Content-Type", contentType);
http.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
HttpResponse response = httpClient.execute(http);
HttpEntity entity = response.getEntity();
String responseStr = EntityUtils.toString(entity);
Map<String, Object> responseMap = new ObjectMapper().readValue(responseStr, Map.class);
String token = responseMap.get("access_token").toString();
System.out.println(token);
}
5. 토큰 받아오기
위코드를 실행하면 아래와 같이 토큰값을 가져오게 된다.
Naver works message 보내기
1. 채널아이디(channelId)
- 아래와 같이 네이버웍스 메신저상에서 확인할수있다.
- 다른방법으로는 메신저 대화창에 /show roomid 를입력하면 채널ID가 제공된다.
2. 봇아이디 (botId)
3. MessageTest.java 메시지 보내기 테스트
위에서 취득한 채널아이디와 봇아이디를 입력하고 메시지 보내기 테스트를 해보자.
...
...
String botId = "0000000"; //봇아이디 입력
String channelId = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"; //채널아이디입력
String apiUrl = "https://www.worksapis.com/v1.0/bots/"+botId+"/channels/"+channelId+"/messages";
String text = "■업무전달 : 테스트업무 입니다. \\n";
String contents = "";
contents += "{\n \"type\" : \"flex\", \n"
+ "\"altText\" : \"[테스트 입니다.]\", \n"
+ "\"contents\" : { \n"
+ "\"type\" : \"bubble\", \n"
+ "\"size\": \"kilo\", \n"
+ "\"body\" : { \n"
+ "\"type\" : \"box\", \n"
+ "\"layout\" : \"vertical\", \n"
+ "\"contents\" : [ \n "
+ "{\n"
+ "\"type\": \"text\", \n"
+ "\"text\": \"[테스트 입니다.]\\n \", \n"
+ "\"wrap\": true, \n"
+ "\"size\": \"md\", \n"
+ "\"weight\": \"bold\" \n"
+ "}, \n "
+ "{ \n"
+ "\"type\": \"text\", \n"
+ "\"text\": \""+text+"\", \n"
+ "\"wrap\": true, \n"
+ "\"size\": \"xs\" \n"
+ "} \n "
+ "] \n"
+ "} \n"
+ "} \n"
+ "}";
HttpPost method = new HttpPost(apiUrl);
method.setHeader("Authorization", "Bearer " + token);
method.setHeader("Content-Type","application/json; charset=UTF-8");
method.setEntity(new StringEntity("{ \"content\" : "+contents+" \r\n }", "UTF-8"));
CloseableHttpClient client = HttpClients.createDefault();
HttpResponse response = client.execute(method);
EntityUtils.toString(response.getEntity(), "UTF-8");
4.메시지봇 결과확인
아래와 같이 naver works에 메시지가 전달된다.