0003. LineBot延伸應用,實作個人銀行帳戶存款查詢、入賬、登入、登出系統

環境

Visual Studio 2015  C#   + MSSQL 2014  + Azure DB
目的:

當用戶加入LineBot後,可以與企業做相關聯的個人資料存取的功能。

這邊以銀行個人用戶查詢、存款、登入、登出做模擬應用

為何: 最近找工作,面試提到的應用課題,覺得很有意思,故而做初步的簡易版本
Github: https://github.com/gotoa1234/LineLoginExample
本篇分為四部分:
一、 銀行餘額情境說明 + 手機上呈現的畫面
二、 開啟LineBot管理者平台,提供選單給使用者
三、 程式碼架構說明(Database)
四、 實作LineAPI的4種功能 + 驗證方法
五、 Line用戶Demo體驗

系列文章:

0001. Azure + LineBot 程式架設教學  :   https://dotblogs.com.tw/milkgreenteaprograme_c_sharp/2016/12/29/001512

0002. 取得機器人好友帳號ID + 發送資料的實作(Line API Push Message)  :  https://dotblogs.com.tw/milkgreenteaprograme_c_sharp/2018/05/13/214926


一、銀行餘額情境說明 + 手機上呈現的畫面


Step 1:以下是系統架構流程圖

Step 2: 對用戶來說,加了Line Bot 的選單畫面:

  說明
1. 登入  用戶必須登入才可以進行 2 , 3的操作
2. 查詢銀行餘額  用戶查詢自己銀行帳戶的金額
3. 修改餘額  用戶需要存款、取款的【模擬操作】
4. 登出  用戶於Line上登出,即可避免他人操作個人資料


 


二、開啟LineBot管理者平台,提供選單給使用者


Step 1:我們進入 Line Manager  -> 管理畫面 ->登入

Step 2:  建立圖文影音內容  -> 圖文選單  -> 新增

Step 3: 以下是各項目說明,如嫌麻煩可以直接複製上面的選項:

使用期間: 在指定的時間範圍內用戶才會看到按鈕選單
標題 按鈕標題
選單顯示設定

 直接選單:一打開LineBot時自動彈開

 用戶點選展開:手動展開

選擇樣板

 選擇樣板 :這邊用內建的圖標,如要客製化可以選

                   【以圖片製作】

選單內容設定

 關鍵字: 抱歉沒研究

 網址:當點擊時,直接彈出URL

 文字:當點擊時,直接幫用戶輸入文字

   

 


三、程式碼架構說明(Database)


Step 1:程式分成3個Libary + 1個MVC Web應用專案

  功能 參考對象
1. LineLoginExample LineBOT API + 登入頁面  2,4
2. CommonLibary  共用的Model  
3. Repository  對DB進行CRUD的操作  2
4. Service  API呼叫時進行商業邏輯的組合  2,3

Step 2 : 記錄到資料庫中的資料表格式如下

/// <summary>
/// 資料表: Line機器人的連絡對象
/// </summary>
public class LineMemberTableModel
{
    /// <summary>
    /// 流水號
    /// </summary>
    public int Sn { get; set; }

    /// <summary>
    /// 唯一碼
    /// </summary>
    public string Id { get; set;}

    /// <summary>
    /// 姓名
    /// </summary>
    public string Name { get; set;}

    /// <summary>
    /// 最後登入時間戳
    /// </summary>
    public DateTime LastLoginTime { get; set; }

    /// <summary>
    /// 帳號餘額
    /// </summary>
    public double AccountBalance { get; set;}


    /// <summary>
    /// 用戶帳號
    /// </summary>
    public string Account { get; set;}

    /// <summary>
    /// 用戶密碼
    /// </summary>
    public string Password { get; set;}
}


四、實作LineAPI的4種功能 + 驗證方法


Step 1:LineBot API 主程式 ,當用戶呼叫時,會先對傳進的字串分析

每當發現沒登入時會回傳 "登入失敗,請先登入帳戶"

※ 程式位置 : LineLoginExample\Controllers\LineBotAPIController.cs

    public class LineBotAPIController : ApiController
    {
        //機器人Token : 仙草奶綠
        string MyLineChannelAccessToken = "XXXXXXXXXXXX";
        /// <summary>
        /// Line機器人回覆API
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("api/LineBotApi/post")]
        public async void Post()
        {
            try
            {
                //取得 http Post RawData(should be JSON)
                string postData = Request.Content.ReadAsStringAsync().Result;
                //剖析JSON
                var ReceivedMessage = isRock.LineBot.Utility.Parsing(postData);
                var bot = new isRock.LineBot.Bot(this.MyLineChannelAccessToken);
                //解析使用者傳給Bot的文字訊息
                string userCommandString = ReceivedMessage.events[0].message.text;
                //Service工作
                LineBotMember _service = new LineBotMember();
                //Return Message
                string message = string.Empty;

                //字串為save表示紀錄 ※實際應用應該偷偷記錄User ID ,這邊是範例
                if (userCommandString == "save")
                {
                    //測試方法: 紀錄
                    _service.InsertID(ReceivedMessage.events[0].source.userId);

                    //回覆API
                    var call = Task.Run(() =>
                    {
                        bot.ReplyMessage(ReceivedMessage.events[0].replyToken,
                            string.Format("紀錄成功: {0}", ReceivedMessage.events[0].source.userId));
                    });
                }
                else if (userCommandString.Contains("取得用戶金額"))//1.取得帳號金額
                {
                    var result = _service.GetAccountBalance(ReceivedMessage.events[0].source.userId);

                    //取得更新後的錢
                    message = ( -1 == result) ? "登入失敗,請先登入帳戶" : string.Format("用戶當前金額: {0}", result);

                    //回覆API
                    var call = Task.Run(() =>
                    {
                        bot.ReplyMessage(
                          ReceivedMessage.events[0].replyToken,
                          message);
                    });
                }
                else if (userCommandString.Contains("更新金額"))//功能2 : 更新金額
                {
                    string get= userCommandString.Substring(4, userCommandString.Length-4);
                    try
                    {
                        double money = double.Parse(get);
                        //更新金額
                        var isSuccess = _service.UpdateAccountBalance(ReceivedMessage.events[0].source.userId, money);
                      
                        //取得更新後的錢
                        var result = _service.GetAccountBalance(ReceivedMessage.events[0].source.userId);

                        message =( false== isSuccess )? "登入失敗,請先登入帳戶" : string.Format("更新成功,當前金額: {0}", result);

                        //回覆API
                        var call = Task.Run(() =>
                        {
                            bot.ReplyMessage(ReceivedMessage.events[0].replyToken,
                                message);
                        });
                    }
                    catch (Exception ex)
                    {
                        //回覆API
                        var call = Task.Run(() =>
                        {
                            bot.ReplyMessage(ReceivedMessage.events[0].replyToken,
                                string.Format("資料格式錯誤"));
                        });
                    } 
                 
                }
                else if (userCommandString == "登出")// 功能4: 登出
                {
                    _service.UpdateSingOut(ReceivedMessage.events[0].source.userId);

                    //回覆API
                    var call = Task.Run(() =>
                    {
                        bot.ReplyMessage(ReceivedMessage.events[0].replyToken,
                            string.Format("登出成功: {0}", DateTime.Now));
                    });
                }


                }
            catch (Exception ex)
            {
                //取得 http Post RawData(should be JSON)
                string postData = Request.Content.ReadAsStringAsync().Result;
                //剖析JSON
                var ReceivedMessage = isRock.LineBot.Utility.Parsing(postData);
                var bot = new isRock.LineBot.Bot(this.MyLineChannelAccessToken);

                //回覆API
                var call = Task.Run(() =>
                {
                    bot.ReplyMessage(ReceivedMessage.events[0].replyToken,
                        string.Format("錯誤資訊:{0}", ex.Message));
                });
            }
        }


    }

Step 2:  登入

※ 程式位置 : Service\LineBot\LineBotMember.cs

/// <summary>
/// 功能 : 登入
/// </summary>
/// <param name="usertoken"></param>
/// <returns></returns>
public bool UpdateLogin(string account ,string password )
{
    bool result = false;
    var allDatas = Repository.Pattern.Factory.RepostioryFactory.LineMemberRepository.GetAllData();
    var getNowUser = allDatas.Where(o => o.Account == account && o.Password == password).FirstOrDefault();
    //判斷是否有正確帳號
    if (null != getNowUser)
    {
        //更新帳號時間戳-視為登入
        result = Repository.Pattern.Factory.RepostioryFactory.LineMemberRepository.UpdateLogin(getNowUser.Id);
    }

    return result;
}

登入成功時,會將Db的時間紀錄為【當下時間】

 

Step 3:  取得UserID (個人用戶)的餘額

※會先檢查登入的時間,如果現在時間 減去 登入時間 相差 60 秒,表示過期,需要重新登入,這是一種簡單的時間戳驗證操作

/// <summary>
/// 功能 : 取得帳號金額
/// </summary>
/// <returns></returns>
public double GetAccountBalance(string userID)
{
    double result = 0;
    var allDatas = Repository.Pattern.Factory.RepostioryFactory.LineMemberRepository.GetAllData();
    //取得餘額
    if (true == IsVerification(userID))
    {
        result = allDatas.Where(o => o.Id == userID).FirstOrDefault().AccountBalance;
    }
    else
    {
        result = -1;
    }
    return result;
}

Step 4:  更新用戶餘額 (模擬存款、取款時的操作)

※會先檢查登入的時間,如果現在時間 減去 登入時間 相差 60 秒,表示過期,需要重新登入,這是一種簡單的時間戳驗證操作

/// <summary>
/// 功能 : 更新金額
/// </summary>
/// <param name="usertoken"></param>
/// <returns></returns>
public bool UpdateAccountBalance(string userID , double balance)
{
    bool result = false;
    var allDatas = Repository.Pattern.Factory.RepostioryFactory.LineMemberRepository.GetAllData();
    //更新餘額
    if (true == IsVerification(userID))
    {
        //更新餘額
        result=  Repository.Pattern.Factory.RepostioryFactory.LineMemberRepository.UpdateAccountBalance(userID, balance);
       
    }

    return result;
}

 

Step 5: 登出

※將時間戳寫為入一個過去時間,這邊是寫 1900-1-1 00:00:00

/// <summary>
/// 功能 : 登出
/// </summary>
/// <param name="usertoken"></param>
/// <returns></returns>
public bool UpdateSingOut(string userID)
{
    bool result = false;
    var allDatas = Repository.Pattern.Factory.RepostioryFactory.LineMemberRepository.GetAllData();
    //登出,時間戳設為過期時間
    if (true == IsVerification(userID))
    {
        result = Repository.Pattern.Factory.RepostioryFactory.LineMemberRepository.UpdateSignOut(userID);
    }

    return result;
}

 


五、Line用戶Demo體驗


Step 1:我們在沒有登入的情況下 點選 【查詢銀行餘額】

LineBOT回應 : 登入失敗,請先登入帳戶

Step 2:於是我們按下 【登入】按鈕,直接跳轉到登入頁面

輸入帳號:20180513 密碼:123456  => Submit 登入 

Step 3 : 顯示登入成功,我們接著回到LineBot 機器人的對話中

Step 4 : 再次 點選 【查詢銀行餘額】

LineBOT回應 : 用戶當前餘額 : 3345678 

Step 5 : 我們嘗試點選 【修改餘額】

LineBot 回應 : 資料格式錯誤 ※ 這是因為我們程式沒做好防呆 (´・ω・`) ,不過知道了指令

Step 6 : 用戶輸入 更新金額 54321

LineBot 回應 : 更新成功 ,當前金額 54321

※接收到了正確的指令,所以進行操作

Step 7 : 最後我們按下【登出】再按下【查詢銀行餘額】

LineBot 回應:登入失敗,請先登入帳戶  ※很明確安全機制是有的