I'm handling user permission in a MVP Winforms application as follows. Here I'll give a full detail of my code as it will be helpful when answering to this question.
My user model has a list called permissions
which holds the permissions of the current user.
(eg: CAN_EDIT_ACCOUNT
)
public class User
{
//
//
List<stirng> Permissions = new List<string>();
}
In Programe.cs
I instantiate required objects and services as follows. Please note that I'm using a single presenter for both login and main views. (Hope MVP doesn't stop me doing that)
Programe.cs
static void Main()
{
frmLogin loginView = new frmLogin (); // Login form
User userModel = new User();
DataService dataService = new DataService();
UserPermissionService ups = new UserPermissionService();
frmMain mainView = new frmMain(); // Application's main window
LoginPresenter presenter = new LoginPresenter(loginView,mainView, userModel, dataService, ups);
presenter.Show();
}
UserPermissionService
is supposed to handle giving permission on request. At the creation of this service in the above code, its not aware of the user as the user is yet to login. So that Method Injection will be used.
There is a bool property for each module or feature that we need to control permission. If the respective permission
is in the permissions
list of the user, the property will be set to True
.
public class UserPermissionService
{
private User _user = null;
public void InjectUser(User user) // User injected
{
_user = user;
}
public bool CanAccessBankAccountModule
{
get { return _user.Permissions.Contains("BANKACCOUNT"); }
}
//
//
}
LOGIN
When the user presses OK
button after supplying user credentials, it will validate it as follows. LoginPresenter
will listen to the OnValidatePassword
event and if its valid then the main window will be loaded and the user will be injected to the UserPermissionService. (please see ValidatePassword()
method in LoginPresenter
code)
public partial class frmLogin : Form
{
private void btnOK_Click(object sender, EventArgs e)
{
OnValidatePassword(sender, e);
}
}
PERMISSION HANDLING
Let's say the main form has buttons for every module and we need to enable a button if the user has permissions to access that particular module (eg. btnBankAccountModule
should be enabled to access BANK ACCOUNT module if the user has permission). There is a public bool property
for every button
in the form and in the Load
event, OnControlPermission
will be fired and LoginPresenter
will listen to this event and it will set the properties True
or False
based on the details provided by the UserPermissionService
. (please see ControlPermission()
method in the LoginPresenter
code)
public partial class frmMain : Form
{
public bool CanAccessBankAccountModule { get; set; }
private void Form1_Load(object sender, EventArgs e)
{
OnControlPermission(sender, e);
btnBankAccountModule.Enabled = CanAccessBankAccountModule;
//
//
}
}
class LoginPresenter
{
frmLogin _LoginView;
frmMain _MainView;
User _Model;
DataService _DataService;
UserPermissionService _UPS;
public LoginPresenter( frmLogin loginView, frmMain mainView, User model, DataService dataService, UserPermissionService ups )
{
_LoginView = loginView;
_MainView = mainView;
_Model = model;
_DataService = dataService;
_UPS = ups;
WireUpEvents();
}
void _MainView_OnControlPermission(object sender, EventArgs e)
{
ControlPermission();
}
private void ControlPermission()
{
_MainView.CanAccessBankAccountModule = _UPS.CanAccessBankAccountModule;
//
//
}
void _View_OnValidatePassword(object sender, EventArgs e)
{
ValidatePassword();
}
private void ValidatePassword()
{
var hash = Encryption.GetHash(_LoginView.UserID, _LoginView.Password);
var user = _DataService.GetPermissions(_DataService.GetUser(_LoginView.UserID));
if (user != null)
{
_Model = user;
var hashInDB = _Model.PassWord;
if (hash != hashInDB)
{
MessageBox.Show("Invalid password");
_LoginView.Valid = false;
}
else
{
_UPS.InjectUser(_Model);
_MainView.PermissionsService = _UPS; //Optional
_MainView.ShowDialog();
}
}
else
{
MessageBox.Show("Invalid user name");
}
}
public void Show()
{
_LoginView.ShowDialog();
}
}
Every thing seems fine up to the main window. My problem is, how should I make the UserPermissinService
available to next level of UIs? (eg. To frmBankAccount
view)
To provide the above service...
- Should my
LoginPresenter
communicate withBankAccountPresenter
?
OR
Could I have a public Property in main form as follows, which will then be passed to subsequent forms?
public UserPermissionService PermissionsService { get; set; }
This property will be set by the
LoginPresenter
with current instance of theUserPermissionService
. (Please see this optional line inLoginPresenter
code;_MainView.PermissionsService = _UPS;
// )Then, when the next presenter is instantiated in the main form... we can pass a reference to the current
UserPermssionService
instance, to the next presenter.var BankAccountPresenter = new BankAccountPresenter(modle, view, dataService, PermissionsService); BankAccountPresenter.Show();
Is it Okay?
OR
- Is it better to instantiate an new instance of
UserPermissionService
in the Main form ? Then how should I inject the current user to the permission service?
Note : I am not familiar with IOC, so I'd appreciate if you could give an other explanation which would go inline with my current work?