네이버웍스 JAVA단에서 Token발행 및 Authorization Code 발행 예제

hanahana·2024년 4월 25일
1

ajax를 쓰지 않고 민감한정보를 최대한 노출하지 않기 위해 java에서 토큰을 받는 방법이다
토큰인증방법은 여기를 참고하였다

접속 URL은 공공형 네이버웍스를 기준으로 한다
공공형이 아닐경우 URL은 전부 기준에 맞춰 구성해야 한다.
공공형과 일반형 URL의 차이는 공식문서에서 확인할수 있다.

Controller작성

MessageTest.java

	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);
		}
} 

		

Authorization 코드 발급 URL만들기

class 이름은 Token.java로 설정

 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();
        }   	
        

    }

Controller에 Authorization 코드 발급URL로 접속할 메소드 구성

MessageTest.java

    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를 원하는 값으로 고치고 다른페이지로 바로 리다이렉트 되도록 수정이 필요하다
현재는 테스트 중이라 작성하지 않았다

받은 코드를 토큰발행 메소드로 보내서 Token값 받기

Token.java

 //토큰발행
	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가 실행된다 이 메소드에서 원하는 작업을 실행할것

	}

Controller

MessageTest.java

	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);
		}
		
	}

주의사항

  1. 토큰을 발행하게 해주는 class RSAUtils는 위에 참고한 출처에 나와있으니 그쪽을 보면된다.
  2. 이 발행방식은 OAuth방식이다, 불편하지만 반드시 네이버웍스에 로그인이 되어있어야만 토큰이 발행가능하다, jwt방식은 로그인 없이 더 간단한데 참고출처에서는 그 방식을 설명하고 있으니 메일같은 민감정보를 사용하지 않는경우에는 이 방식을 사용할필요 없다.
  3. 토큰은 24시간을 기준으로 만료되기에 만료시에만 재 발행되도록 만들어져있다.
  4. redirect uri는 발급한 api의 redircect url과 동일해야한다, 공식문서상에서는 https만 가능하다고 나와있으나 실제로 로컬호스트 http에서도 작동했다.
  5. 봇이 메세지를 보낼 방에는 봇이 반드시 초대되어있어야만 메세지 전송이 가능하다
  6. private키를 private.key로 이름 변경후 resources폴더에 넣어줘야 한다
profile
hello world

0개의 댓글