ajax를 쓰지 않고 민감한정보를 최대한 노출하지 않기 위해 java에서 토큰을 받는 방법이다
토큰인증방법은 여기를 참고하였다
접속 URL은 공공형 네이버웍스를 기준으로 한다
공공형이 아닐경우 URL은 전부 기준에 맞춰 구성해야 한다.
공공형과 일반형 URL의 차이는 공식문서에서 확인할수 있다.
private static boolean isExpired = false;
private static String accessToken = "";
@RequestMapping(value = {"/naverWorks/botTest.do"})
public static void testMsg(HttpServletResponse res) throws Exception {
//토큰이 없거나 만료시 토큰생성
if("".equals(accessToken) || isExpired ) {
Token.authorization("bot", res);
isExpired = false;
}else {
testMsg2(res, accessToken);
}
}
private static String accessToken;
//Authorization Code 발행
public static void authorization(String scope, HttpServletResponse response) throws Exception {
String code = "";
try {
String AuthorizationUrl = "https://auth.gov-naverworks.com/oauth2/v2.0/authorize";
String ClientID = "클라이언트아이디"; // 여기에 클라이언트 ID를 입력하세요
String RedirectURL = "http://ip주소 및 포트/authorizationCode.do"; // 여기에 Redirect URI를 입력하세요
String responseType = "code";
String state = "test"; // CSRF를 방지하기 위한 클라이언트 측의 인증값
// 파라미터를 URL 인코딩하여 추가
Map<String, String> paramMap = new HashMap<>();
paramMap.put("client_id", ClientID);
paramMap.put("redirect_uri", RedirectURL);
paramMap.put("scope", scope);
paramMap.put("response_type", responseType);
paramMap.put("state", state);
StringBuilder urlBuilder = new StringBuilder(AuthorizationUrl + "?");
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
urlBuilder.append(entry.getKey())
.append("=")
.append(URLEncoder.encode(entry.getValue(), "UTF-8"))
.append("&");
}
String finalUrl = urlBuilder.toString();
finalUrl = finalUrl.substring(0, finalUrl.length() - 1); // 맨 끝의 & 제거
System.out.println("Request URL: " + finalUrl);
MessageTest.testCode(response, finalUrl); //코드를 받는 메소드로 연결
} catch (Exception e) {
e.printStackTrace();
}
}
public static void testCode(HttpServletResponse response, String url) throws IOException {
response.sendRedirect(url);
}
//RedirectURL로 연결될 컨트롤러
@RequestMapping(value = { "/authorizationCode.do" })
public void authorizationCode(HttpServletRequest request, HttpServletResponse response) throws Exception {
String code = request.getParameter("code");
String state = request.getParameter("state");
code = code.replaceAll("==", "");
HashMap<String, String> codeMap = new HashMap<String, String>();
Token.tokenString(code, response); //토큰발행 메소드로 연결
}
이 컨트롤러에서 코드값을 전송한다
하지만 /naverWorks/botTest.do로 연결된 페이지가 /authorizationCode.do페이지로 이동됨으로 void를 원하는 값으로 고치고 다른페이지로 바로 리다이렉트 되도록 수정이 필요하다
현재는 테스트 중이라 작성하지 않았다
//토큰발행
public static void tokenString(String code, HttpServletResponse res) 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);
RSAPublicKey publicKey = null;
RSAPrivateKey privateKey = RSAUtils.getPrivateKey("private.key"); // resources-local 폴더안에 있는 파일
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", "authorization_code"));
params.add(new BasicNameValuePair("code", code)); //위에 작성한 클래스에서 받아온 코드값
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")); //매개변수로 scope입력 ex) "bot" / "mail"
URI uri = new URI("https://auth.gov-naverworks.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);
accessToken =responseMap.get("access_token").toString();
MessageTest.testMsg2(res, accessToken); //여기에서 api가 실행된다 이 메소드에서 원하는 작업을 실행할것
}
public static void testMsg2(HttpServletResponse res, String accessTokenStr) throws Exception {
accessToken = accessTokenStr;
String botId = "봇아이디"; //봇아이디 입력
String channelId = "채널아이디"; //채널아이디입력 (봇이 멤버로 추가된 채널만 가능)
String apiUrl = "https://gov.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 " + accessToken);
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);
String Error = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(Error);
response.getStatusLine().getProtocolVersion();
//토큰만료 후 코드 재 실행
if(response.getStatusLine().getStatusCode() == 401) {
isExpired = true;
testMsg(res);
}
}