첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.

728x90
반응형
728x170

TestProject.zip
0.02MB

▶ KakaoAPIHelper.cs

using System.Windows.Forms;

using Newtonsoft.Json.Linq;

using RestSharp;

namespace TestProject
{
    /// <summary>
    /// 카카오 API 헬퍼
    /// </summary>
    public class KakaoAPIHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 애플리케이션 ID - ApplicationID

        /// <summary>
        /// 애플리케이션 ID
        /// </summary>
        public string ApplicationID { get; protected set; }

        #endregion
        #region REST API 키 - RESTAPIKey

        /// <summary>
        /// REST API 키
        /// </summary>
        public string RESTAPIKey { get; protected set; }

        #endregion
        #region 리다이렉트 URL - RedirectURL

        /// <summary>
        /// 리다이렉트 URL
        /// </summary>
        public string RedirectURL { get; protected set; }

        #endregion
        #region 인증 코드 - AuthenticationCode

        /// <summary>
        /// 인증 코드
        /// </summary>
        public string AuthenticationCode { get; protected set; }

        #endregion
        #region 액세스 토큰 - AccessToken

        /// <summary>
        /// 액세스 토큰
        /// </summary>
        public string AccessToken { get; protected set; }

        #endregion
        #region 갱신 토큰 - RefreshToken

        /// <summary>
        /// 갱신 토큰
        /// </summary>
        public string RefreshToken { get; protected set; }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - KakaoAPIHelper(applicationID, restAPIKey, redirectURL)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="applicationID">애플리케이션 ID</param>
        /// <param name="restAPIKey">REST API 키</param>
        /// <param name="redirectURL">리다이렉트 URL</param>
        public KakaoAPIHelper(string applicationID, string restAPIKey, string redirectURL)
        {
            ApplicationID = applicationID;
            RESTAPIKey    = restAPIKey;
            RedirectURL   = redirectURL;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public
        
        #region 로그인 URL 구하기 - GetLoginURL()

        /// <summary>
        /// 로그인 URL 구하기
        /// </summary>
        /// <returns>로그인 URL</returns>
        public string GetLoginURL()
        {
            return $"https://kauth.kakao.com/oauth/authorize?response_type=code&client_id={RESTAPIKey}&redirect_uri={RedirectURL}&scope=talk_message,friends";
        }

        #endregion
        #region 인증 코드 설정하기 - SetAuthenticationCode(authenticationCodeURL)

        /// <summary>
        /// 인증 코드 설정하기
        /// </summary>
        /// <param name="authenticationCodeURL">인증 코드 URL</param>
        public void SetAuthenticationCode(string authenticationCodeURL)
        {
            string authenticationCode = authenticationCodeURL.Substring(authenticationCodeURL.IndexOf("=") + 1);

            if(authenticationCodeURL.CompareTo($"{RedirectURL}?code={authenticationCode}") == 0)
            {
                AuthenticationCode = authenticationCode;
            }
            else
            {
                AuthenticationCode = null;
            }
        }

        #endregion

        #region 액세스 토큰 설정하기 - SetAccessToken()

        /// <summary>
        /// 액세스 토큰 설정하기
        /// </summary>
        public void SetAccessToken()
        {
            RestClient client = new RestClient();

            RestRequest request = new RestRequest("https://kauth.kakao.com/oauth/token", Method.POST);

            request.AddParameter("grant_type"  , "authorization_code");
            request.AddParameter("client_id"   , RESTAPIKey          );
            request.AddParameter("redirect_uri", RedirectURL         );
            request.AddParameter("code"        , AuthenticationCode  );

            IRestResponse response = client.Execute(request);

            if(response.IsSuccessful)
            {
                JObject responseObject = JObject.Parse(response.Content);

                AccessToken  = responseObject["access_token" ].ToString();
                RefreshToken = responseObject["refresh_token"].ToString();
            }
        }

        #endregion
        #region 액세스 토큰 갱신하기 - UpdateAccessToken()

        /// <summary>
        /// 액세스 토큰 갱신하기
        /// </summary>
        public void UpdateAccessToken()
        {
            RestClient client = new RestClient();

            RestRequest request = new RestRequest("https://kauth.kakao.com/oauth/token", Method.POST);

            request.AddParameter("grant_type"   , "refresh_token");
            request.AddParameter("client_id"    , RESTAPIKey     );
            request.AddParameter("refresh_token", RefreshToken   );

            IRestResponse response = client.Execute(request);

            if(response.IsSuccessful)
            {
                JObject responseObject = JObject.Parse(response.Content);

                AccessToken  = responseObject["access_token" ].ToString();

                if(responseObject["refresh_token"] != null)
                {
                    RefreshToken = responseObject["refresh_token"].ToString();
                }
            }
        }

        #endregion

        #region 로그인 하기 - Login()

        /// <summary>
        /// 로그인 하기
        /// </summary>
        /// <returns>처리 결과</returns>
        public bool Login()
        {
            LoginForm form = new LoginForm(this);

            form.ShowInTaskbar = false;
            form.StartPosition = FormStartPosition.CenterScreen;

            DialogResult result = form.ShowDialog();

            return (result == DialogResult.OK);
        }

        #endregion
        #region 로그아웃 하기 - Logout()

        /// <summary>
        /// 로그아웃 하기
        /// </summary>
        /// <returns>처리 결과</returns>
        public bool Logout()
        {
            RestClient client = new RestClient();

            RestRequest request = new RestRequest("https://kapi.kakao.com/v1/user/unlink", Method.POST);

            request.AddHeader("Authorization", $"bearer {AccessToken}");

            AuthenticationCode = null;
            AccessToken        = null;

            return client.Execute(request).IsSuccessful;
        }

        #endregion

        #region 나에게 커스텀 메시지 보내기 - SendCustomMessageToMySelf(message)

        /// <summary>
        /// 나에게 커스텀 메시지 보내기
        /// </summary>
        /// <param name="message">메시지</param>
        /// <returns>처리 결과</returns>
        public bool SendCustomMessageToMySelf(JObject templateObject)
        {
            RestClient client = new RestClient();

            RestRequest request = new RestRequest("https://kapi.kakao.com/v2/api/talk/memo/default/send", Method.POST);

            request.AddHeader("Authorization", $"bearer {AccessToken}");

            request.AddParameter("template_object", templateObject);

            return client.Execute(request).IsSuccessful;
        }

        #endregion
        #region 나에게 템플리트 메시지 보내기 - SendTemplateMessageToMySelf(templateMessageID)

        /// <summary>
        /// 나에게 템플리트 메시지 보내기
        /// </summary>
        /// <param name="templateMessageID">템플리트 메시지 ID</param>
        /// <returns>처리 결과</returns>
        public bool SendTemplateMessageToMySelf(string templateMessageID)
        {
            RestClient client = new RestClient();

            RestRequest request = new RestRequest("https://kapi.kakao.com/v2/api/talk/memo/send", Method.POST);

            request.AddHeader("Authorization", $"bearer {AccessToken}");

            request.AddParameter("template_id", templateMessageID);

            return client.Execute(request).IsSuccessful;
        }

        #endregion
    }
}

 

▶ LoginForm.cs

using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 로그인 폼
    /// </summary>
    public partial class LoginForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 카카오 API 헬퍼
        /// </summary>
        private KakaoAPIHelper kakaoAPIHelper;

        /// <summary>
        /// 로그인 URL
        /// </summary>
        private string loginURL = null;

        /// <summary>
        /// 시도 카운트
        /// </summary>
        private int tryCount = 0;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public
        
        #region 생성자 - LoginForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public LoginForm(KakaoAPIHelper helper)
        {
            this.kakaoAPIHelper = helper;

            InitializeComponent();

            this.webBrowser.ScriptErrorsSuppressed = true;

            this.webBrowser.DocumentCompleted += webBrowser_DocumentCompleted;

            this.loginURL = this.kakaoAPIHelper.GetLoginURL();

            this.webBrowser.Navigate(this.loginURL);
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 웹 브라우저 문서 완료시 처리하기 - webBrowser_DocumentCompleted(sender, e)

        /// <summary>
        /// 웹 브라우저 문서 완료시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            string url = this.webBrowser.Url.ToString();

            if(this.loginURL == url)
            {
            }
            else
            {
                this.kakaoAPIHelper.SetAuthenticationCode(url);

                if(!string.IsNullOrEmpty(this.kakaoAPIHelper.AuthenticationCode))
                {
                    this.kakaoAPIHelper.SetAccessToken();

                    DialogResult = DialogResult.OK;

                    Close();
                }
                else
                {
                    if(this.tryCount < 3)
                    {
                        this.tryCount++;

                        this.webBrowser.Navigate(this.loginURL);
                    }
                    else
                    {
                        DialogResult = DialogResult.Cancel;

                        Close();
                    }
                }
            }
        }

        #endregion
    }
}

 

▶ MainForm.cs

using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Windows.Forms;

using Newtonsoft.Json.Linq;

namespace TestProject
{
    /// <summary>
    /// 메인 폼
    /// </summary>
    public partial class MainForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 카카오 API 헬퍼
        /// </summary>
        private KakaoAPIHelper kakaoAPIHelper;

        /// <summary>
        /// 애플리케이션 ID
        /// </summary>
        private readonly string applicationID = "[애플리케이션 ID를 설정한다.]";

        /// <summary>
        /// REST API 키
        /// </summary>
        private readonly string restAPIKey = "[REST API 키를 설정한다.]";

        /// <summary>
        /// 리다이렉트 URL
        /// </summary>
        private readonly string redirectURL = "[Redirect URI를 설정한다.]";

        /// <summary>
        /// 메시지 템플리트 ID
        /// </summary>
        private readonly string messageTemplateID = "[메시지 템플릿 ID를 설정한다.]";

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            this.kakaoAPIHelper = new KakaoAPIHelper(this.applicationID, this.restAPIKey, this.redirectURL);

            Load                              += Form_Load;
            this.loginButton.Click            += loginButton_Click;
            this.refreshTokenButton.Click     += refreshTokenButton_Click;
            this.sendToMySelfSendButton.Click += sendToMySelfSendButton_Click;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 폼 로드시 처리하기 - Form_Load(sender, e)

        /// <summary>
        /// 폼 로드시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_Load(object sender, EventArgs e)
        {
            string applicationFileName = $"{Process.GetCurrentProcess().ProcessName}.exe";

            SetRegistryKeyForWebBrowserControl(applicationFileName);
        }

        #endregion
        #region 로그인 버튼 클릭시 처리하기 - loginButton_Click(sender, e)

        /// <summary>
        /// 로그인 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void loginButton_Click(object sender, EventArgs e)
        {
            if(this.loginButton.Text == "로그인")
            {
                bool result = this.kakaoAPIHelper.Login();

                if(result)
                {
                    this.loginButton.Text = "로그아웃";
                }
            }
            else
            {
                bool result = this.kakaoAPIHelper.Logout();

                if(result)
                {
                    this.loginButton.Text = "로그인";
                }
            }
        }

        #endregion
        #region 토큰 갱신 버튼 클릭시 처리하기 - refreshTokenButton_Click(sender, e)

        /// <summary>
        /// 토큰 갱신 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void refreshTokenButton_Click(object sender, EventArgs e)
        {
            this.kakaoAPIHelper.UpdateAccessToken();
        }

        #endregion

        #region 보내기 버튼 클릭시 처리하기 (나에게 발송) - sendToMySelfSendButton_Click(sender, e)

        /// <summary>
        /// 보내기 버튼 클릭시 처리하기 (나에게 발송)
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void sendToMySelfSendButton_Click(object sender, EventArgs e)
        {
            if(this.sendToMySelfCustomMessageRadioButton.Checked)
            {
                SendCustomMessageToMySelf(this.sendToMySelfMessageTextBox.Text);

                this.sendToMySelfMessageTextBox.Text = string.Empty;
            }
            else
            {
                SendTemplateMessageToMySelf();
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 웹 브라우저 컨트롤용 레지스트 키 설정하기 - SetRegistryKeyForWebBrowserControl(applicationFileName)

        /// <summary>
        /// 웹 브라우저 컨트롤용 레지스트 키 설정하기
        /// </summary>
        /// <param name="applicationFileName">애플리케이션 파일명</param>
        /// <remarks>WebBrowser 컨트롤을 Internet Explorer 11 버전으로 동작하도록 해준다.</remarks>
        private void SetRegistryKeyForWebBrowserControl(string applicationFileName)
        {
            RegistryKey registryKey = null;

            try
            {
                registryKey = Registry.LocalMachine.OpenSubKey
                (
                    @"SOFTWARE\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION",
                    true
                );

                if(registryKey == null)
                {
                    MessageBox.Show(this, "해당 레지스트리 키를 찾을 수 없습니다.");

                    return;
                }

                string registryKeyValue = Convert.ToString(registryKey.GetValue(applicationFileName));

                if(registryKeyValue == "11001")
                {
                    registryKey.Close();

                    return;
                }

                if(string.IsNullOrEmpty(registryKeyValue))
                {
                    registryKey.SetValue(applicationFileName, unchecked((int)0x2AF9), RegistryValueKind.DWord);
                }

                registryKeyValue = Convert.ToString(registryKey.GetValue(applicationFileName));

                if(registryKeyValue == "11001")
                {
                    MessageBox.Show(this, "IE11 레지스트리 설정이 완료되었습니다.");
                }
                else
                {
                    MessageBox.Show(this, $"IE11 레지스트리 설정을 실패했습니다.\n키 값 : {registryKeyValue}");
                }
            }
            catch(Exception exception)
            {
                MessageBox.Show(this, $"IE11 레지스트리 설정시 에러가 발생했습니다.\n{exception}");
            }
            finally
            {
                if(registryKey != null)
                {
                    registryKey.Close();
                }
            }
        }

        #endregion

        #region 나에게 커스텀 메시지 보내기 - SendCustomMessageToMySelf(message)

        /// <summary>
        /// 나에게 커스텀 메시지 보내기
        /// </summary>
        /// <param name="message">메시지</param>
        private void SendCustomMessageToMySelf(string message)
        {
            JObject linkObject = new JObject();

            linkObject.Add("web_url"       , "https://icodebroker.tistory.com");
            linkObject.Add("mobile_web_url", "https://icodebroker.tistory.com");

            JObject templateObject = new JObject();

            templateObject.Add("object_type" , "text"       );
            templateObject.Add("text"        , message      );
            templateObject.Add("link"        , linkObject   );
            templateObject.Add("button_title", "링크로 이동");

            bool result = this.kakaoAPIHelper.SendCustomMessageToMySelf(templateObject);

            if(result)
            {
                MessageBox.Show(this, "커스텀 메시지 전송을 성공했습니다.");
            }
            else
            {
                MessageBox.Show(this, "커스텀 메시지 전송을 실패했습니다.");
            }
        }

        #endregion
        #region 나에게 템플리트 메시지 보내기 - SendTemplateMessageToMySelf()

        /// <summary>
        /// 나에게 템플리트 메시지 보내기
        /// </summary>
        private void SendTemplateMessageToMySelf()
        {
            bool result = this.kakaoAPIHelper.SendTemplateMessageToMySelf(this.messageTemplateID);

            if(result)
            {
                MessageBox.Show(this, "템플리트 메시지 전송을 성공했습니다.");
            }
            else
            {
                MessageBox.Show(this, "템플리트 메시지 전송을 실패했습니다.");
            }
        }


        #endregion
    }
}

 

※ 관리자 권한으로 실행해야 한다.

728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요