-1

I want to create role-based permissions for each form. How method simple can I apply?. please guide me.

If logged in as the owner then he can access to all forms while if logged in as an admin then the main form for the update button cannot be used and there is a messagebox that the user does not have access and also the admin can display form2 but button1 cannot be used and there is a messagebox that the user does not have access.

This is only a sample because the original project has many forms.

Thanks

Code in Form1 (Login)

Public Class Form1
    Private uService As New UserService()

    Private Sub BtnLogin_Click(sender As Object, e As EventArgs) Handles BtnLogin.Click
        'add dapper logics here 
        Dim users = uService.GetDTOUsersByUsername(txtUsername.Text)
        If users.Password = txtPassword.Text AndAlso users.Username = txtUsername.Text Then
            MessageBox.Show("Successfull, Welcome " & users.RoleName)
            Me.ShowInTaskbar = False
            Me.Hide()
            Call (New FrmMain()).ShowDialog()
            Environment.Exit(0)
        Else
            MessageBox.Show("Invalid Login details")
        End If
    End Sub
End Class
Public Class UserService
    Public Function GetOledbConnectionString() As String
        Return "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\dapperdemo.accdb;Persist Security Info=False;"
    End Function
    Private ReadOnly _conn As OleDbConnection
    Private _connectionString As String = GetOledbConnectionString()
    Public Sub New()
        _conn = New OleDbConnection(_connectionString)
    End Sub
    Public Function GetUserByUsername(ByVal Username As String) As Users
        Dim sql = $"SELECT  * FROM Users WHERE Username = '{Username}'"
            Using _conn = New OleDbConnection(GetOledbConnectionString())
            Return _conn.Query(Of Users)(sql).FirstOrDefault()
        End Using
    End Function
    Public Function GetUserByRolename(ByVal Rolename As String) As Role
        Dim sql = $"SELECT  RoleName FROM Users WHERE Username = '{Rolename}'"
        Using _conn = New OleDbConnection(GetOledbConnectionString())
            Return _conn.Query(Of Role)(sql).FirstOrDefault()
        End Using
    End Function
    Public Function GetDTOUsersByUsername(ByVal Username As String) As DTOUsers
        Dim sql = $"SELECT * FROM Users INNER JOIN Role ON Users.Roleid = Role.Roleid"
        Using _conn = New OleDbConnection(GetOledbConnectionString())
            Return _conn.Query(Of DTOUsers)(sql).FirstOrDefault()
        End Using
    End Function
End Class
Public Class Users
    Public Property Username() As String
    Public Property Password() As String
    Public Property RoleID() As Integer

End Class
Public Class Role
    Public Property RoleID() As Integer
    Public Property RoleName() As String
End Class
Public Class DTOUsers
    Public Property Username() As String
    Public Property Password() As String
    Public Property RoleName() As String

End Class

Code in FormMain

Public Class FrmMain
    Private Sub Button2BtnShowform2_Click(sender As Object, e As EventArgs) Handles BtnShowform2.Click
        Dim frm As New Form2
        frm.ShowDialog()
    End Sub
End Class

Table : Users

Username password RoleID
TEST1 TEST@123 1
TEST2 TEST@1234 2

Table : Role

Roleid RoleName
1 Owner
2 Admin

Form1(Login)

Form1(Login)

FrmMain

FrmMain

Form2

Form2

roy
  • 693
  • 2
  • 11
  • You need to fix those SQL injection vulnerabilities. – Joel Coehoorn Aug 23 '23 at 00:24
  • @JoelCoehoorn , thanks your reply, you mean ` SQL injection vulnerabilities` is there anything wrong with my sql code? please guide me – roy Aug 23 '23 at 13:37
  • Yes, there's something wrong. It is **NEVER** okay to use string concatenation or interpolation to put data into a query (as is done with, ie, `Username = '{Rolename}'`). That's **really bad**, and _WILL_ result in your app getting hacked. You **need** a mechanism to send the RoleName data to the database separate from the SQL command text... and that mechanism is called "Parameterized Queries". There is a TON of information on the web for this. Go take the time to do some research. – Joel Coehoorn Aug 23 '23 at 14:24
  • _(Side note: there are some ORMs that hook into the FormatProvider used with string interpolation to do parameterized queries... but that isn't happening here, and they are still doing parameterized queries.)_ – Joel Coehoorn Aug 23 '23 at 14:25
  • While I'm here I also see a password field on the form. Whatever you do, NEVER store actual passwords in a database. You need a per-user salt prepended (not append) to the password. Then cryptographically hash the result (which is not reversible). This destroys the original password. Only the hash remains; this is what you save. When someone tries to log in, you repeat the process for the attempted password and compare hashes; NEVER compare passwords. This is made much easier via NuGet libraries like BCrypt.Net, and is too important to **ever** do wrong, even for practice/learning projects. – Joel Coehoorn Aug 23 '23 at 14:31
  • @JoelCoehoorn , Thank you for your suggestion. `Username = '{Rolename}' ` but I use this no error and this is at this [link](https://github.com/Drizin/DapperQueryBuilder/) . It should be like this `Username = '?Rolename?' ` this alternative syntax is a Dapper thing called "pseudo-positional parameters", where it rewrites that at runtime with the OLEDB positional syntax. [link](https://riptutorial.com/dapper/example/13835/pseudo-positional-parameters--for-providers-that-don-t-support-named-parameters-) – roy Aug 23 '23 at 14:34
  • @JoelCoehoorn , for this `BCrypt.Net` please guide me – roy Aug 23 '23 at 14:36
  • That's a whole other level. There's lots of information out there. Explore some on your own first and then come back to ask questions about it as you encounter specific issues. – Joel Coehoorn Aug 23 '23 at 15:40

1 Answers1

0

Kind of feel this should be a comment rather than an answer, but this is really a big topic so probably not going to fit there. This really is more of a software design and logic question rather than anything specific with troubleshooting coding/tooling so possible even out of scope for this forum. As such I'm just going to keep this all kind of conceptual without going too far into exact implementation details. There are also many different ways to tackle this problem, so while this makes sense to me, others will have different opinions.

While there are likely many 3rd party libraries and tools that will help with this I really don't know how or if they could be implemented retrospectively. It's up to you to find and elevate these for your purposes.

The type of security you are talking about here is really best implemented at the start of your development. Guessing you've just dived straight into coding the app without considering things like security.

Ideally what you would have been best to do is create a Base Form which implements your security logic via the Form.Load() event (Or maybe somewhere else in the form event cycle). Possibly some "overridable" methods that get called from the Load event. Using the overridable method pattern will mean you can customize logic on individual forms.

Then when adding new forms to your application, you would inherit this base class. One thing to be aware of when overriding the Form.Load on inherited forms, you will need to call the base load event.

With that in mind, considering you've already got many forms in your application there two options if you want to do this type of pattern.

  1. You can create your base form implementing the desired security logic, then modify the existing forms (the designer.vb file) to inherit your new base form.

  2. Implement the security logic in each form.

If it where me, I would go with option 1, the Base for gives you ability to standardise look and feel and implement common controls etc.

Hursey
  • 541
  • 2
  • 8
  • 17