Access Database Security Alternative


Access Database Security Alternative

Security without Work Group Administrator

Access Database Security Alternative: database security can be a challenging aspect to MS Access database creation. Working with the workgroup administration tool and setting the security levels can be confusing at times.

Additionally, if you have multiple Access databases on the computer and you set workgroup security for one then you’ll need to join the workgroup for all databases.  This can be maddening especially if you are a developer like me with literally 100’s of Access databases.

After setting up security with passwords your database is not secure at all since anyone can purchase a Microsoft Office product password cracker/hacker and break into the database.  Because of this situation we never setup Access databases with workgroup security.  We have created a fairly simple method for implementing user-level and group  security with a simple table of permissions/password and a subroutine to set form update properties.  We combine this with a few settings in the database to make it difficult for a user to get into the code or into the tables.

Detailed below is an example of one method for implementing a simple yet effective database security scheme for Microsoft Access databases.

Here are the goals of this method:

  • Avoid use of the Workgroup administrator

  • Eliminate ability of password cracker/hacker software to break into the database

  • Easy security maintenance by the database administrator and easy program maintenance for the programmer.

There are four components involved in the implementation of the security method.

  • An Employees table that contains attributes about the employee and the user password.

  • A tabbed user interface to facilitate to facilitate implementation of the security method

  • A subroutine to read and set appropriate security settings on the form and subform

  • Database settings and VB code to prevent user from breaking directly into the tables and the VB code.

Here is the L_Employees table:

L_Employees Employee_ID Username Password Access_Level 15 AndreaF ******* A 14 HeidiH ****** M 3 HollyW ******** A 5 JenniferC ***** M 6 JodyB ******** A 7 JonE ***** A 1 Joe *** M 8 KristalD ******* M 9 MariaH ***** M 10 MaryC ********** A 11 MaryW ******* A 12 RussellN ***** A 13 ScottR ******* A 2 TinaC ****** M

Note the Access_Level field – M is for Managers (full access); A is for Artists (partial access).

When the database opens the On Open event is activated and the following VB code runs:

Private Sub Form_Open(Cancel As Integer)
‘    initialize global variables
‘    Hide tabs
Me.TabCtl0.Pages.Item(0).Caption = “Welcome”
Me.TabCtl0.Pages.Item(1).Visible = False
Me.TabCtl0.Pages.Item(2).Visible = False
Me.TabCtl0.Pages.Item(3).Visible = False
Me.TabCtl0.Pages.Item(4).Visible = False

username = Environ(“Username”)


End Sub

Here is the set_globals routine and get_globals functions.  Put them into a Module:

Option Compare Database

Global GBL_employee_ID As Long
Global GBL_Access_Level As String

Function set_globals()
GBL_employee_ID = 0
End Function

Public Function get_global(gname As String)
Select Case gname
Case “Employee_ID”
get_global = GBL_employee_ID
End Select
End Function

Place the above code in a new module and you can name the new module anything you like – the important part is the ‘Global GBL_Access_Level As String’ line that must come after the Option Compare Databse and before the Option Explicit line.

The result is a login form on the welcome screen of the tabbed interface:

(Click to view full size image)

After the correct username and password has been entered then the following subroutine is called.  Here is the login subroutine code:

(note that some lines are wrapped because of page width limitations)
Private Sub Login_btn_Click()
‘ ************************************* login sequence
On Error GoTo local_err
DoCmd.RunCommand acCmdSaveRecord

‘ set global access level to failsafe no access then lookup access level

GBL_Access_Level = “X”
GBL_Access_Level = Nz(DLookup(“Access_Level”, “L_Employees”, “Username='” & Nz(Me.USername, ” “) & “‘ and password='” & Nz(Me.Password, ” “) & “‘”), “X”)

‘    examine results of username/password lookup

If GBL_Access_Level = “X” Then
MsgBox “Invalid Username or Password… try again.”
Exit Sub
End If

‘ get employee id

GBL_employee_ID = Nz(DLookup(“Employee_ID”, “L_Employees”, “Username='” & Nz(Me.USername, ” “) & “‘ and password='” & Nz(Me.Password, ” “) & “‘”), “X”)

‘set welcome to include users name or invalid logon if bad logon

Me.TabCtl0.Pages.Item(0).Caption = “Welcome ” & Nz(DLookup(“employee_name”, “L_Employees”, “employee_id=” & get_global(“Employee_ID”)), “Invalid Login”)

‘ setup privs based on artist or manager


‘  call subroutine to set access to forms

Call set_privs

‘ reset login screen fields

Me.USername = “”
Me.Password = “”
Exit Sub

‘ error handler

MsgBox “unexpected error= ” & Err.Description
Resume ok_exit
Exit Sub

Below is the subroutine to set privileges and show/hide menu tabs.  Note that we use a simple case statement to examine user access level and set visibility of tabs and properties of appropriate forms.  For the limited access ‘A’ – Artists the Reports and Lists tab are hidden since only the managers can run reports and modify list data (including passwords and usernames).

Public Sub set_privs()

Form_F_Projects.Form.AllowAdditions = False
Form_F_Projects.Form.AllowDeletions = False
Form_F_Projects.Form.AllowEdits = False
Form_F_Projects.Form.AllowFilters = False

Form_F_Project_Actions.Form.AllowAdditions = True
Form_F_Project_Actions.Form.AllowDeletions = True

‘status field is updateable by everyone

Form_F_Project_Status_Only.Form.AllowEdits = True
Form_F_Project_Status_Only.Form.AllowAdditions = True

Select Case GBL_Access_Level
Case “M” ‘ manager

Me.TabCtl0.Pages.Item(1).Visible = True
Me.TabCtl0.Pages.Item(2).Visible = True
Me.TabCtl0.Pages.Item(3).Visible = True
Me.TabCtl0.Pages.Item(4).Visible = True

Form_F_Projects.Form.AllowEdits = True
Form_F_Projects.Form.AllowAdditions = True
Form_F_Projects.Form.AllowDeletions = True

Form_F_Project_Products.Form.AllowEdits = True
Form_F_Project_Products.Form.AllowAdditions = True
Form_F_Project_Products.Form.AllowDeletions = True

Form_F_Project_Status_Only.Form.AllowEdits = True
Form_F_Project_Status_Only.Form.AllowAdditions = True

Form_F_Project_Actions.Form.AllowEdits = True
Form_F_Project_Actions.Form.AllowAdditions = True
Form_F_Project_Actions.Form.AllowDeletions = True


Case “A” ‘ artist

Me.TabCtl0.Pages.Item(1).Visible = True
Me.TabCtl0.Pages.Item(2).Visible = True

Form_F_Project_Products.Form.AllowAdditions = False
Form_F_Project_Products.Form.AllowDeletions = False
Form_F_Project_Products.Form.AllowEdits = False

Form_F_Project_Status_Only.Form.AllowEdits = True
Form_F_Project_Status_Only.Form.AllowAdditions = True

Form_F_Project_Actions.Form.AllowEdits = True
Form_F_Project_Actions.Form.AllowAdditions = True
Form_F_Project_Actions.Form.AllowDeletions = True


End Select

Here is the resulting main menu after security settings – all tabs are available in this case:

(Click to view full size image)

The last part of the security setup for this database is to restrict artists viewing of project data.  Artists are only allowed to modify certain fields of their own projects.  And, are only allowed to review their own projects.

Here is the query record source for the main projects form:

SELECT M_Projects.Project_ID, M_Projects.ProjectName, M_Projects.Manager_ID, M_Projects.DateOpened, M_Projects.Project_Status_ID, M_Projects.Due_Date, M_Projects.Artist_ID, M_Projects.DateClosed, M_Projects.Agent_ID, M_Projects.Sale_Rep_ID, M_Projects.RouteTo, M_Projects.BillTo_ID, M_Projects.ProjectPaidDate, M_Projects.Project_Type_ID, M_Projects.FarmList, M_Projects.Indicia_ID, M_Projects.Design_ID, M_Projects.Output_Spec_ID, M_Projects.Files_Submitted, M_Projects.Payment_Method_ID, M_Projects.Comments, M_Projects.Date_Modified, M_Projects.Modified_By
FROM M_Projects
WHERE (((M_Projects.Artist_ID) In (select employee_id from Q_Employee_Access_List) Or (M_Projects.Artist_ID)=0));

(note that (M_Projects.Artist_ID)=0) allows new projects to be created)

Below is the SQL code for the Q_Employee_Access_List query referenced above

SELECT L_Employees.Employee_ID
FROM L_Employees
WHERE (((L_Employees.Employee_ID)=get_global(’employee_id’))) OR (((get_global(‘access_level’))=”M”));

The combination of these two queries limits access to project data.  Artists with an ‘A’ access level can only see their own projects and Managers with ‘M’ access level can see all projects.  The individual form setting defined in the Set_Privs subroutine (above) determines who can modify data in which forms.


Finally, you can see that once setup, this method for applying security and access levels to databases is fairly easy to implement.  The method is also flexible since additional levels access can be added by simply adding more Select Case statements in the Set_Privs subroutine.

We have developed a simplified downloadable Access Security Alternative database example.  You can find this running example in our new Access Database Downloads.

Alternative To Access Security

Record-Level Security Method


Microsoft Office VBA, MS Access 2003, 2007, 2010, 2013, 2016