MFCで物品購入承認システム作成 4

前回までの話。

MFCで物品購入承認システム作成 1

MFCで物品購入承認システム作成 2

MFCで物品購入承認システム作成 3

ログインチェック作成

いよいよユーザテーブルからログイン可否の判断を行おうと思います。

まず準備として、手動でテーブルにデータを二つ追加しておきます。
違いは、ユーザ権限が1と0です。
パスワードも今は適当で。

Visual Studioに戻ります。

今回、一度ログインするとユーザIDとユーザ名と管理者権限の有無は保持しておきたいので、
SupplyRequestManager.hに、変数とセットゲット関数を加えておきます。

private:
	CString	m_strUserId;	// ユーザID
	CString	m_strUserName;	// ユーザ名
	BOOL	m_bUserAuth;	// 管理者権限

public:
	// ユーザID取得
	CString strGetUserId() { return m_strUserId; }
	// ユーザID設定
	void SetUserId(CString strUserId) { m_strUserId = strUserId; }

	// ユーザ名取得
	CString strGetUserName() { return m_strUserName; }
	// ユーザ名設定
	void SetUserName(CString strUserName) { m_strUserName = strUserName; }

	// 管理者権限取得
	BOOL bGetUserAuth() { return m_bUserAuth; }
	// 管理者権限設定
	void SetUserAuth(BOOL bUserAuth) { m_bUserAuth = bUserAuth; }

メンバ変数は、SupplyRequestManager.cppで初期化も忘れずに。

続きまして、MySQLManager.hに、ログインチェック用の関数を追加。

public:

	//ログインチェック
	BOOL bCheckLogin(CString strId, CString strPassword);

MySQLManager.cppで具体的な処理を書きます。

/**
 * @fn
 * @brief	ログインチェック
 * @param	CString strId       ログインID
 *          CString strPassword ログインパスワード
 * @return	TRUE    ログイン成功
 *          FALSE   ログイン失敗
 */
BOOL CMySQLManager::bCheckLogin(CString strId, CString strPassword)
{
    try
    {
        m_con->setSchema(SCHEMA);   // スキーマ選択

        sql::SQLString sqlStrId = strConverter(strId);        // 型変換
        sql::SQLString sqlStrPass = strConverter(strPassword);  // 型変換

        sql::SQLString strSqlQuery = "SELECT * FROM " + TABLE_USER +  " WHERE Id = '" + sqlStrId + "' AND Password = '" + sqlStrPass + "'";

        // クエリを実行
        std::unique_ptr<sql::PreparedStatement> pstmt(m_con->prepareStatement(strSqlQuery));

        std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

        CString strUserName = _T("");
        BOOL bUserAuth = FALSE;
        if (!res->next())
        {
            AfxMessageBox(_T("Idまたはパスワードが見当たらない"));
            return FALSE;
        }
        else
        {
            // userテーブルに該当が存在した
            std::string strCol = res->getString("Name");        // 名前列から名前取得
            strUserName = strConvertFromUTF8ToUTF16(strCol);    // 変換
            int iAuth = res->getInt("Authority");               // 権限列から取得
            if (iAuth == 1)
                bUserAuth = TRUE;

            //ログイン情報保持
            CSupplyRequestManagerApp* pApp = static_cast<CSupplyRequestManagerApp*>(AfxGetApp());
            pApp->SetUserId(strId);         // ユーザID設定
            pApp->SetUserName(strUserName); // ユーザ名設定
            pApp->SetUserAuth(bUserAuth);   // 管理者権限設定
        }
    }
    catch (sql::SQLException& e)
    {
        // 実行できなかった
        ErrSQLException(e);
        return FALSE;
    }

    return TRUE;
}

簡単に解説

  • 15~16行目:エディットボックスで取得したIDとパスワードを、
    前回作成した関数で型変換。
  • 18~23行目:SQL文作成&クエリ実行。
  • 27~30行目:userテーブルにそのIDとパスワードの組み合わせは存在しないようです。
  • 34~39行目:存在したので、名前とIDを該当行から取得します。
  • 42~45行目:メンバ変数にセットしています。(※)
  • 48~53行目:どうやらtry文(基本的に21か23行目)でエラーが生じたようで。

※について。
AfxGetAppは、アプリケーション全体にアクセスする手段を提供し、
アプリケーションのライフタイムに渡って状態を保持したい場合に使います。
ここら辺は、もっと詳しく解説しているところがあると思うので…。

テーブルからデータを取得する処理が終わりました。
いよいよ、ログイン画面でこれらを使います。

Login.cppを開きます。
まずはヘッダーインクルード。

#include "MySQLManager.h"

続いてOKボタンが押されたときの関数OnBnClickedOk内に処理を追加します。

/**
 * @fn
 * @brief	OKボタン押下時の処理
 * @param	なし
 * @return	なし
 */
void CLogin::OnBnClickedOk()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	UpdateData(TRUE);

	CMySQLManager Login;
	Login.GetConnection();	//接続確立
	if (Login.bCheckLogin(m_strLoginID, m_strLoginPassword))
	{
		CDialog::OnOK();
	}
	else
	{
		//何もしない
	}
}

エディットボックスから文字列を取得し、
MySQLManagerでログインチェックを行います。

最後に、ちゃんと該当のデータが取れているか確認します。

SupplyRequestManagerDlg.cppのOnInitDialogに、以下を追加します。

BOOL CSupplyRequestManagerDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	//略

	// TODO: 初期化をここに追加します。
	CStatic* pStatic = (CStatic*)GetDlgItem(IDC_STATIC_MAIN_WELCOME);	//Welcomeスタティック
	CSupplyRequestManagerApp* pApp = static_cast<CSupplyRequestManagerApp*>(AfxGetApp());
	CString strMes = _T("Welcome! ") + pApp->strGetUserName();	// Welcome!○○の形
	pStatic->SetWindowText(strMes);

	if (pApp->bGetUserAuth() == FALSE)
	{
		// 一般ユーザの場合

		// 申請承認ボタンは非表示
		CButton* pButton = (CButton*)GetDlgItem(IDC_BUTTON_MAIN_APPROVAL);
		pButton->ShowWindow(SW_HIDE);
		// ユーザ情報管理ボタンは非表示
		pButton = (CButton*)GetDlgItem(IDC_BUTTON_MAIN_USERLIST);
		pButton->ShowWindow(SW_HIDE);
		// 項目情報管理ボタンは非表示
		pButton = (CButton*)GetDlgItem(IDC_BUTTON_MAIN_ITEMLIST);
		pButton->ShowWindow(SW_HIDE);

		SetWindowText(_T("物品購入システム"));  //タイトル
	}
	else
	{
		SetWindowText(_T("物品購入システム(管理者用)"));  //タイトル
	}

	return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
}

メイン画面のWelcomeにユーザ名が出てきます。

また、管理者権限がある場合(Authority列が1)は全ボタンが表示されますが、
一般ユーザの場合は申請ボタンだけ表示させます。

動作確認

さて、ビルドします。
ちょっとドキドキしています。

まずは普通に、テーブルに用意したIDとパスワードで試します。

すると

名前も取得でき、管理者であることが分かります。

今度は一般ユーザの方で。

これもよさそう。

さて、テーブルにないIDとパスワードを入れると

動いてますね(´▽`*)。
良かった良かった。

問題点

ちょっと動かして問題点を見つけたので。

IDが5桁未満の場合

IDが00000、パスワードが12345では当然ログインできます。

ところがIDを0にしてもログインできたんですよね。
Id列がint型ですからね。

対応としては

  1. テーブルの列をvarcharに変更する
    →文字列としてみてくれるので、0と00000は別物
  2. エディットボックスに制御をかける
    5桁未満の場合はSQLの実行処理へ行かない、など。

2の方が実際の修正としては現実的なので、制御かけます。

Login.cpp内で。

void CLogin::OnBnClickedOk()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	UpdateData(TRUE);

	if (m_strLoginID.GetLength() < 5)
	{
		AfxMessageBox(_T("ログインIDは5桁で入力してください。"));
		return;
	}

	CMySQLManager Login;
	Login.GetConnection();	//接続確立
	if (Login.bCheckLogin(m_strLoginID, m_strLoginPassword))
	{
		CDialog::OnOK();
	}
	else
	{
		//何もしない
	}
}

ログインIDが5桁未満の場合は抜ける処理を追加です。

これで、IDが「0000」と入力されても6行目で引っかかって、
テーブルに見に行く処理が為されません。

終わりに

今回はユーザテーブルからログインを決定する処理を作りました。

ログイン機能の処理自体はほぼ終わりですが、
パスワードを生のままで保存するのはセキュリティ上よろしくないので、
次回以降ハッシュ化関数を作ります。

今回はここまで。

MFCで物品購入承認システム作成 5
前回までの話。MFCで物品購入承認システム作成 1MFCで物品購入承認システム作成 2MFCで物品購入承認システム作成 3MFCで物品購入承認システム作成 4管理リスト画面作成今回はユーザ情報に関する処理を。ユーザ関連は今回と次回の2回で終...

コメント

タイトルとURLをコピーしました