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にして、ダイアログボックスを表示して終了です。
コメント