【Access VBA】ログインフォームを使ったシステムの作り方

Accessでユーザーがそれぞれログインしてあれやこれやするシステムを作ることになりました。

Webで検索するといくつか方法が出てくるのですが、パスワードを平文で保存するタイプでした。テーブルを見られても問題ないようにハッシュ値を使う方法を採用したいところ。

今回はほとんどCopilotで調べました。他の生成AIと比較はしていないのですが、VBAはCopilotが相性良いと思うんですよね。

システムの流れとオブジェクトの解説

Accessデータベースを開くと「F_ログイン」というフォームが開きます。

社員コードとパスワードを入力してログインします。

この画面ではログイン以外のことはさせたくないので、リボンとナビゲーションは非表示にしています。

ログイン後の画面です。ユーザーにはシステム管理者権限を付与でき、これはシステム管理者用の「F_メニュー_管理」というフォームです。

このフォームではリボンとナビゲーションが表示されます。

管理者用メニューの「社員登録」を押すと「F_社員登録」のフォームが表示されます。登録をするとそのユーザー情報でログインできるようになります。

システム管理者ではない一般ユーザー用の「F_メニュー」です。ここでは社員登録ボタンはありません。

システム管理者か否かで表示するフォームを変えているだけなので、それぞれのフォームで表示するオブジェクトを設定します。

M_社員マスタ

ログイン情報は「M_社員マスタ」というテーブルに保存しています。

実際に値が入っている様子がこんな感じ。

リボンやナビゲーションを非表示にすることでこのテーブルを開けないようにはしているものの、いくらでも抜け道はありますので、最初から見られてもいいようにパスワードを平文ではなくハッシュ値にしています。

データベースの設定

データベースの設定です。

フォームの表示は「F_ログイン」にして起動時に開くフォームを選択しています。

「ステータスバーを表示する」と「ナビゲーション ウィンドウを表示する」のチェックを外しています。

VBA

Module1

Option Compare Database

Function GetMD5Hash(strInput As String) As String
    Dim xmlObj As Object
    Dim byteData() As Byte
    Dim hashValue As String
    Dim i As Integer

    Set xmlObj = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
    byteData = StrConv(strInput, vbFromUnicode)
    
    Dim hash() As Byte
    hash = xmlObj.ComputeHash_2(byteData)

    For i = 0 To UBound(hash)
        hashValue = hashValue & LCase(Right("0" & Hex(hash(i)), 2))
    Next i

    GetMD5Hash = hashValue
End Function

標準モジュールにGetMD5Hash()という関数を用意します。

これは引数に指定された文字列をMD5でハッシュ値にして返す関数です。

この関数はログインと社員登録をする時にパスワードをハッシュ化するのに使います。

MD5を使うために.NET Framework 3.5を有効にする

この関数は.NET Framework 3.5というランタイムが有効になっていないと使えません。

Windowsのコントロールパネルからプログラム → プログラムと機能と進み、「Windowsの機能の有効化または無効化」を開き、「.NET Framework 3.5 (.NET 2.0 および 3.0 を含む)」を有効化します。有効化した後は念のため再起動しておきましょう。

ところでMD5は脆弱性が見つかっており、CRYPTRECの政府推奨暗号リストから外されています。現在はSHA-256が推奨されていて、SHA-256を使うバージョンもネットで調べたら出てきます。

今回あえてMD5を使っているのは、SHA-256よりも処理速度が速く、少しでも負担を減らすためです。とは言っても実感できるレベルではないですし、特にこだわりがなければSHA-256を使う方がいいですね。

今回はそれほどセキュリティレベルを求めないものを作ったのでMD5にしましたが、破られると致命的なシステムであればSHA-256の方がいいでしょう。というかそんなセキュリティを求められるシステムならAccessは使わない方がいい気がします。

F_ログイン

Option Compare Database

Private Sub Form_Open(Cancel As Integer)
    DoCmd.ShowToolbar "Ribbon", acToolbarNo
    DoCmd.SelectObject acForm, "", True
    DoCmd.RunCommand acCmdWindowHide
End Sub

Private Sub tx社員コード_KeyPress(KeyAscii As Integer)
    '数字(0~9)とバックスペースのみ許可
    If Not (KeyAscii >= 48 And KeyAscii <= 57) And KeyAscii <> 8 Then
        KeyAscii = 0
    End If
End Sub

Private Sub cmdログイン_Click()
    Dim rs As DAO.Recordset
    Dim frm As Form
    
    If IsNull(Me.tx社員コード) = True Or IsNull(Me.txパスワード) = True Then
        MsgBox "社員コードまたはパスワードが入力されていません。", vbCritical
        Exit Sub
    End If
    
    Set rs = CurrentDb.OpenRecordset("SELECT * FROM M_社員マスタ WHERE 社員コード = '" & Me.tx社員コード & "' AND パスワード = '" & GetMD5Hash(Me.txパスワード.Value) & "'")
    
    If Not rs.EOF Then
        If rs!システム管理者 = True Then
            'ナビゲーションとリボンを表示
            DoCmd.ShowToolbar "Ribbon", acToolbarYes
            DoCmd.SelectObject acTable, , True
            
            DoCmd.OpenForm "F_メニュー_管理"
            Set frm = Forms("F_メニュー_管理")
        Else
            DoCmd.OpenForm "F_メニュー"
            Set frm = Forms("F_メニュー")
        End If
        
        frm.Controls("labelメッセージ").Caption = "お疲れさまです、" & rs!氏名 & " 様"

        DoCmd.Close acForm, "F_ログイン"
    Else
        MsgBox "社員コードまたはパスワードが間違っています。", vbExclamation
    End If
    
    rs.Close
    Set rs = Nothing
End Sub

Form_Openでこのフォームが開いた時にリボンとナビゲーションを非表示にさせます。このフォームはデータベースを開いた時に最初に開くフォームですし、ログアウトで戻ってくるフォームでもありますので、前後の状態に関係なくリボンとナビゲーションを非表示にするようにしておきます。

tx社員コード_KeyPressについては、入力を数字とバックスペースのみにします。全角入力を回避するのはオブジェクトのIMEをオフにすることで対応しています。ついでにパスワードもIMEをオフにしています。*で非表示してくれますが、何も設定しないと全角で入ってしまいます。

cmdログイン_Clickでログイン時の挙動を書いています。社員コードとハッシュ化したパスワードが一致するレコードをM_社員マスタから探してきます。rs.EOFは最終レコード、つまりレコードが見つかって最終レコードではない場合はログイン処理に進みます。ここでシステム管理者であればリボンとナビゲーションを表示させます。

あとlabelメッセージに氏名を組み合わせて「お疲れさまです、{氏名} 様」と表示させています。このように取得できたレコードのフィールドをオブジェクトに表示させることができます。

F_メニュー

Option Compare Database

Private Sub cmdログアウト_Click()
    DoCmd.OpenForm "F_ログイン"
    DoCmd.Close acForm, "F_メニュー"
End Sub

メニューにログアウト以外の機能はないのでF_ログインを開いて、このF_メニューを閉じる動作のみです。

F_メニュー_管理

Option Compare Database

Private Sub cmdログアウト_Click()
    DoCmd.OpenForm "F_ログイン"
    DoCmd.Close acForm, "F_メニュー_管理"
End Sub

Private Sub cmd社員登録_Click()
    DoCmd.OpenForm "F_社員登録"
End Sub

F_メニュー_管理もF_社員登録を開くボタンが追加されているだけでほとんど同じです。

ログアウトするとF_ログインが開いた時点でリボンとナビゲーションが非表示にされます。

F_社員登録

Option Compare Database

Private Sub tx社員コード_KeyPress(KeyAscii As Integer)
    '数字(0~9)とバックスペースのみ許可
    If Not (KeyAscii >= 48 And KeyAscii <= 57) And KeyAscii <> 8 Then
        KeyAscii = 0
    End If
End Sub

Private Sub cmd登録_Click()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim sql As String
    
    If IsNull(Me.tx氏名) = True Then
        MsgBox "氏名が入力されていません。", vbCritical
        Exit Sub
    End If
    
    If IsNull(Me.tx社員コード) = True Then
        MsgBox "社員コードが入力されていません。", vbCritical
        Exit Sub
    End If
    
    If IsNull(Me.txパスワード) = True Then
        MsgBox "パスワードが入力されていません。", vbCritical
        Exit Sub
    End If
    
    If Me.txパスワード <> Me.txパスワード確認用 Then
        MsgBox "パスワード(確認用)が入力されたパスワードと一致しません。"
        Exit Sub
    End If
    
    sql = "SELECT 社員コード FROM M_社員マスタ WHERE 社員コード = '" & Me.tx社員コード & "'"
    
    Set db = CurrentDb
    Set rs = db.OpenRecordset(sql, dbOpenSnapshot)
    If Not rs.EOF Then
        MsgBox "社員コード: " & Me.tx社員コード & "は既に登録されています。"
        Exit Sub
    End If
    
    Set rs = db.OpenRecordset("M_社員マスタ", dbOpenDynaset)
    
    rs.AddNew
    rs!社員コード = Me.tx社員コード.Value
    rs!氏名 = Me.tx氏名.Value
    rs!パスワード = GetMD5Hash(Me.txパスワード.Value)
    rs!システム管理者 = Me.checkシステム管理者
    
    rs.Update
    Set rs = Nothing
    Set db = Nothing
    
    Me.tx氏名 = Null
    Me.tx社員コード = Null
    Me.txパスワード = Null
    Me.txパスワード確認用 = Null
    Me.checkシステム管理者 = False
    
    MsgBox "社員が登録されました。", vbInformation
    
End Sub

ログイン画面と同様にtx社員コードには数字とバックスペースのみ受け付けるようにしています。

あとは各項目が入力されているかチェックし、パスワードも確認用と一致していればパウスァーどをハッシュ化してM_社員マスタに登録します。

登録後は各オブジェクトをNullにして、ダイアログボックスを表示して終了です。

コメント

コメントする前にお読みください

迷惑コメント防止のために初回のコメント投稿は承認制のため、投稿が反映されるまで少し時間がかかります。もちろん荒らしは承認しません。

教えて君やクレクレ君に対しては回答しませんのでご了承ください。