NEWS

[C#] Hướng dẫn sử dụng tài khoản Google Account đăng nhập vào hệ thống winform

[C#] Hướng dẫn sử dụng tài khoản Google Account đăng nhập vào hệ thống winform
Đăng bởi: Thảo Meo - Lượt xem: 15801 08:01:21, 07/11/2020C#   In bài viết

Xin chào các bạn, bài viết hôm nay mình sẽ hướng dẫn các bạn cách đăng nhập vào hệ thống winform sử dụng tài khoản Google Account trong lập trình C# Winform.

[C#] Login App with google account

Hiện nay, các bạn các bạn đều thấy các website hay ứng dụng, thường có thêm chắc năng đăng nhập phần mềm hoặc website sử dụng tài khoản của mạng xã hội tích hợp, làm cho việc đăng ký và đăng nhập phần mềm một cách dễ dàng và nhanh chóng cho người dùng.

Các mạng xã hội support login như: Google, Facebook, Zalo...

Trong bài viết này mình sẽ viết ứng dụng, đăng nhập vào hệ thống Winform sử dụng tài khoản Google Account.

Video demo ứng dụng Login with google account c#:

Dưới đây là giao diện demo form login của mình sử dụng Guna2 Framework để thiết kế giao diện:

google_login

và khi các bạn bấm vào login with Google, thì hệ thống sẽ mở website đăng nhập với tài khoản Google như hình bên dưới:

loginwithgoogle

Và dưới đây là hình ảnh mình lấy dữ liệu từ google trả về khi đăng nhập thành công.

login_goole

Đầu tiên để nhập được, các bạn cần vào console google developer để tạo một ứng dụng và xin quyền lấy thông tin tài khoản của người dùng.

Khi tạo ứng dụng xong, app ứng dụng sẽ cung cấp cho chúng ta 2 khóa: clientidclientSecret

public const string clientId = "662959790489-sqt6ja2lqj5hnd4o7g7ki4jg7j0okvl5.apps.googleusercontent.com";
public const string clientSecret = "pJFA5xdGQ-MbRdEniXIseRH-";

Khi có hai khóa của ứng dụng xong, chúng ta sẽ xin quyền lấy thông tin profile của người dùng qua Scope sau:

  string scopes = "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile";

Sau khi có đủ thông tin chúng ta sẽ đưa chúng vào hàm GetAutenticationURI() để lấy về đường dẫn yêu cầu đăng nhập và mở lên bằng trình duyệt Chrome.

public static Uri GetAutenticationURI(string clientId, string redirectUri)
{
    string scopes = "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile";

    if (string.IsNullOrEmpty(redirectUri))
    {
        redirectUri = "urn:ietf:wg:oauth:2.0:oob";
    }
    string oauth = string.Format("https://accounts.google.com/o/oauth2/auth?client_id={0}&redirect_uri={1}&scope={2}&response_type=code", clientId, redirectUri, scopes);
    return new Uri(oauth);
}

Khi mở đường dẫn này thành công, google sẽ hiện ra các tài khoản chúng ta đang đăng nhập trong session để cho chúng ta chọn 1 tài khoản để đăng nhập.

Khi chọn thành công, google sẽ trả cho chúng ta một khóa AppoveCode như hình bên dưới:

login_csharp

Khi có được mã code này, chúng ta sẽ sử dụng AutomationElement để Hook vào trình duyệt chrome và lấy mã code này trả về ứng dụng.

Để lấy được mã code này trả về mình sẽ sử dụng một background worker để chạy và detect tab google đang active có chứa mã code chúng ta sẽ trả về cho ứng dụng winform.

Và khi có mã Appovedcode này, chúng ta sẽ truy vấn đến địa chỉ website API theo đường dẫn sau, để lấy thông Access_Token:

public static AuthResponse Exchange(string authCode, string clientid, string secret, string redirectURI)
{

    var request = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");

    string postData = string.Format("code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type=authorization_code", authCode, clientid, secret, redirectURI);
    var data = Encoding.ASCII.GetBytes(postData);

    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = data.Length;

    using (var stream = request.GetRequestStream())
    {
        stream.Write(data, 0, data.Length);
    }

    var response = (HttpWebResponse)request.GetResponse();

    var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

    var x = AuthResponse.get(responseString);

    x.clientId = clientid;
    x.secret = secret;

    return x;

}

Khi truy vấn thành công, chúng ta sẽ được mã Access_Token.

Và chúng ta sẽ tiếp tục truy cập lấy thông tin profile người dùng qua mã Access Token này.

 var url = $"https://www.googleapis.com/oauth2/v3/userinfo?access_token={access.Access_token}";

Khi các bạn truy cập theo cú pháp vậy, dữ liệu chúng ta sẽ nhận được về dạng Json như hình bên dưới:

login_google_demo

và chúng ta chỉ cần lấy thông tin này để hiển thị vào ứng dụng Winform của mình.

Source code FrmMain:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Automation;
using System.Windows.Forms;

namespace LoginGoogleAccount
{
    public partial class FrmLogin : Form
    {

        private static FrmLogin _defaultInstance;
        public static FrmLogin Default
        {
            get
            {
                if (_defaultInstance == null || _defaultInstance.IsDisposed)
                {
                    _defaultInstance = new FrmLogin();

                }
                return _defaultInstance;
            }
            set => _defaultInstance = value;
        }
        public FrmLogin()
        {
            InitializeComponent();        
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            guna2AnimateWindow1.SetAnimateWindow(this);    
            guna2ShadowForm1.SetShadowForm(this);    
        }

        private void guna2CirclePictureBox1_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void btn_LoginGoogle_Click(object sender, EventArgs e)
        {
            var url = AuthResponse.GetAutenticationURI(clientId, redirectURI).ToString();
            Process.Start(url);          
            Thread.Sleep(1000);
            DisplayMemoryUsageInTitleAsync();
        }

        public const string clientId = "662959790489-sqt6ja2lqj5hnd4o7g7ki4jg7j0okvl5.apps.googleusercontent.com";
        public const string clientSecret = "pJFA5xdGQ-MbRdEniXIseRH-";
        public const string redirectURI = "urn:ietf:wg:oauth:2.0:oob";
        public bool flag = true;

        public AuthResponse access;

       
        private void GetProfile(string approveCode)
        {
            access = AuthResponse.Exchange(approveCode, clientId, clientSecret, redirectURI);
            //AccessToken.Text = access.Access_token;
            //refreshToken.Text = access.refresh_token;

            //if (DateTime.Now < access.created.AddHours(1))
            //{
            //    Expire.Text = access.created.AddHours(1).Subtract(DateTime.Now).Minutes.ToString();
            //}
            var url = $"https://www.googleapis.com/oauth2/v3/userinfo?access_token={access.Access_token}";
            var wc = new WebClient();          
            wc.Headers.Add(HttpRequestHeader.AcceptCharset, "utf-8");
            wc.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/55.0");
            wc.Encoding = Encoding.UTF8;
            var jsonProfile = wc.DownloadString(url);
            var frm = new FrmProfile(jsonProfile);
            frm.Show();
            this.Hide();
        }

        private void DisplayMemoryUsageInTitleAsync()
        {
            BackgroundWorker wrkr = new BackgroundWorker();
            wrkr.WorkerReportsProgress = true;

            wrkr.DoWork += (object sender, DoWorkEventArgs e) => {

                bool result;
                while (result = GetAppoveCodeGoogle())
                {
                    wrkr.ReportProgress(0, result);
                    Thread.Sleep(100);
                }

                wrkr.Dispose();
                Process[] procsChrome = Process.GetProcessesByName("chrome");
                foreach (Process chrome in procsChrome)
                {
                    if (chrome.MainWindowHandle == IntPtr.Zero)
                        continue;

                    AutomationElement element = AutomationElement.FromHandle(chrome.MainWindowHandle);
                    if (element != null)
                    {
                        Condition conditions = new AndCondition(
                       new PropertyCondition(AutomationElement.ProcessIdProperty, chrome.Id),
                       new PropertyCondition(AutomationElement.IsControlElementProperty, true),
                       new PropertyCondition(AutomationElement.IsContentElementProperty, true),
                       new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));

                        AutomationElement elementx = element.FindFirst(TreeScope.Descendants, conditions);
                        var url = ((ValuePattern)elementx.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
                        if (url.Contains("accounts.google.com/o/oauth2/approval/v2/approvalnativeap"))
                        {
                            ((ValuePattern)elementx.GetCurrentPattern(ValuePattern.Pattern)).SetValue("https://laptrinhvb.net");
                            ChromeWrapper chromes = new ChromeWrapper();

                            chromes.SendKey((char)13, chrome);//enter
                            var arr = url.Split('&');
                            var approvalCode = WebUtility.HtmlDecode(arr[arr.Length - 1].Replace("approvalCode=", ""));
                            this.BeginInvoke(new Action(() =>
                            {
                                GetProfile(approvalCode);
                            }));                           
                        }
                    }
                }
                wrkr.Dispose();
            };
            wrkr.RunWorkerAsync();
        }

        public bool GetAppoveCodeGoogle()
        {
            Process[] procsChrome = Process.GetProcessesByName("chrome");
            foreach (Process chrome in procsChrome)
            {
                if (chrome.MainWindowHandle == IntPtr.Zero)
                    continue;

                AutomationElement element = AutomationElement.FromHandle(chrome.MainWindowHandle);
                if (element != null)
                {
                    Condition conditions = new AndCondition(
                   new PropertyCondition(AutomationElement.ProcessIdProperty, chrome.Id),
                   new PropertyCondition(AutomationElement.IsControlElementProperty, true),
                   new PropertyCondition(AutomationElement.IsContentElementProperty, true),
                   new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));

                    AutomationElement elementx = element.FindFirst(TreeScope.Descendants, conditions);
                    var url = ((ValuePattern)elementx.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
                    if (url.Contains("accounts.google.com/o/oauth2/approval/v2/approvalnativeap"))
                    {
                        var arr = url.Split('&');
                        var approvalCode = WebUtility.HtmlDecode(arr[arr.Length - 1].Replace("approvalCode=", ""));
                        return false;
                    }

                }


            }
            return true;
        }
    }
}

Tạo một class AuthResponse.cs với nội dung sau:

using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using System.Net;
using System.IO;

namespace LoginGoogleAccount
{
    public class AuthResponse
    {
        private string access_token;
        public string Access_token
        {
            get
            {            
                // Access token lasts an hour if its expired we get a new one.
                if (DateTime.Now.Subtract(created).Hours > 1)
                {
                    refresh();
                }
                return access_token;
            }
            set { access_token = value; }
        }
        public string refresh_token { get; set; }
        public string clientId { get; set; }
        public string secret { get; set; }
        public string expires_in { get; set; }
        public DateTime created { get; set; }        

     
        public static AuthResponse get(string response)
        {
            AuthResponse result = JsonConvert.DeserializeObject<AuthResponse>(response);
            result.created = DateTime.Now;   // DateTime.Now.Add(new TimeSpan(-2, 0, 0)); //For testing force refresh.
            return result;
        }


        public void refresh()
        {
            var request = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");
            string postData = string.Format("client_id={0}&client_secret={1}&refresh_token={2}&grant_type=refresh_token", this.clientId, this.secret, this.refresh_token);
            var data = Encoding.ASCII.GetBytes(postData);

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

            var response = (HttpWebResponse)request.GetResponse();
            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
            var refreshResponse = AuthResponse.get(responseString);
            this.access_token = refreshResponse.access_token;
            this.created = DateTime.Now;
        }


        public static AuthResponse Exchange(string authCode, string clientid, string secret, string redirectURI)
        {

            var request = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");

            string postData = string.Format("code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type=authorization_code", authCode, clientid, secret, redirectURI);
            var data = Encoding.ASCII.GetBytes(postData);

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

            var response = (HttpWebResponse)request.GetResponse();

            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

            var x = AuthResponse.get(responseString);

            x.clientId = clientid;
            x.secret = secret;

            return x;

        }



        public static Uri GetAutenticationURI(string clientId, string redirectUri)
        {
            string scopes = "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile";

            if (string.IsNullOrEmpty(redirectUri))
            {
                redirectUri = "urn:ietf:wg:oauth:2.0:oob";
            }
            string oauth = string.Format("https://accounts.google.com/o/oauth2/auth?client_id={0}&redirect_uri={1}&scope={2}&response_type=code", clientId, redirectUri, scopes);
            return new Uri(oauth);
        }

    }
}

Class Form Profile.cs để hiển thị thông tin người dùng:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace LoginGoogleAccount
{
    public partial class FrmProfile : Form
    {
  

        public string jsonProfile;
        public FrmProfile(string json)
        {
            InitializeComponent();
            guna2ShadowForm1.SetShadowForm(this);
            this.jsonProfile = json;
        }

      
        protected override void OnShown(EventArgs e)
        {
            var profile = JsonConvert.DeserializeObject<Profile>(jsonProfile);
            pic_Profile.LoadAsync(profile.picture);
            txt_firstname.Text = profile.family_name;
            txt_lastName.Text = profile.given_name;
            txt_email.Text = profile.email;
            txt_fullname.Text = profile.name;
            WindowHelper.BringProcessToFront(Process.GetCurrentProcess());
            base.OnShown(e);
          
        }
    
        private void guna2CirclePictureBox2_Click(object sender, EventArgs e)
        {
            this.Close();
            FrmLogin.Default.Show();
        }

        public class Profile
        {
            public string sub { get; set; }
            public string name { get; set; }
            public string given_name { get; set; }
            public string family_name { get; set; }
            public string picture { get; set; }
            public string email { get; set; }
            public bool email_verified { get; set; }
            public string locale { get; set; }
        }
    }

    public static class WindowHelper
    {
        public static void BringProcessToFront(Process process)
        {
            IntPtr handle = process.MainWindowHandle;
            if (IsIconic(handle))
            {
                ShowWindow(handle, SW_RESTORE);
            }

            SetForegroundWindow(handle);
        }

        const int SW_RESTORE = 9;

        [System.Runtime.InteropServices.DllImport("User32.dll")]
        private static extern bool SetForegroundWindow(IntPtr handle);
        [System.Runtime.InteropServices.DllImport("User32.dll")]
        private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
        [System.Runtime.InteropServices.DllImport("User32.dll")]
        private static extern bool IsIconic(IntPtr handle);
    }
}

Tạo một class ChromeWrapper.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LoginGoogleAccount
{
    public class ChromeWrapper
    {
        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);  
        private static uint WM_KEYDOWN = 0x100, WM_KEYUP = 0x101;
        private Process chromeProcess;

        public ChromeWrapper()
        {
        }
        public void SendKey(char key, Process process_chrome)
        {
            try
            {
                if (process_chrome.MainWindowHandle != IntPtr.Zero)
                {                   
                    SendMessage(process_chrome.MainWindowHandle, ChromeWrapper.WM_KEYDOWN, (IntPtr)key, IntPtr.Zero);                  
                    Thread.Sleep(30); 
                    SendMessage(process_chrome.MainWindowHandle, ChromeWrapper.WM_KEYUP, (IntPtr)key, IntPtr.Zero);
                }
            }
            catch (Exception e) 
            {
            }
        }
    }
}

Để đơn giản, các bạn có thể download source code bên dưới về tham khảo.

Thanks for watching!

DOWNLOAD SOURCE

THÔNG TIN TÁC GIẢ

BÀI VIẾT LIÊN QUAN

[C#] Hướng dẫn sử dụng tài khoản Google Account đăng nhập vào hệ thống winform
Đăng bởi: Thảo Meo - Lượt xem: 15801 08:01:21, 07/11/2020C#   In bài viết

CÁC BÀI CÙNG CHỦ ĐỀ

Đọc tiếp
.