Does anyone have an actual example of how to use int RefId as proposed in this question?
I am trying to get authentication going but I need to marry up the userAuth data with my own user table. The problem is I have no idea how to pass an additional parameter to the "/register" method. I guess I'm looking for an event like "OnAddUser" which will allow me to throw some additional parameters into the mix.
I managed to get the user registration working pretty quickly, it was super easy. Maybe the problem is that it was too easy? I can see it work but I can't figure out how to get between it and the database.
Either the dictionary approach or the RefId approach will probably work for me, it's just no obvious to me how use either.
Is it possible to override the create user altogether? I found this code:
MyServices.cs
which looks like it's doing the create user in place of "/register" but there are some other articles that suggest that you can't override the ServiceStack DTOs, you have to use the default tables.
You could include your own Register Service by using a copy of the RegisterService source code and modify it to suit your needs, e.g. Use a custom Register DTO with the additional properties you want.
But you can easily pass additional params without changing the existing Register DTO by adding it to the ?querystring which you can access inside your Services with:
var myParam = base.Request.QueryString["myParam"];
Otherwise the way to add your Custom Logic during registration or Authentication is to tap into the existing Session or Auth Events.
TechStacks has an example of this in its CustomAuthUserSession:
public class CustomUserSession : AuthUserSession
{
public string DefaultProfileUrl { get; set; }
public string GithubProfileUrl { get; set; }
public string TwitterProfileUrl { get; set; }
public override void OnAuthenticated(IServiceBase authService,
IAuthSession session,
IAuthTokens tokens,
Dictionary<string, string> authInfo)
{
base.OnAuthenticated(authService, session, tokens, authInfo);
var appSettings = authService.TryResolve<IAppSettings>();
var userAuthRepo = authService.TryResolve<IAuthRepository>();
var userAuth = userAuthRepo.GetUserAuth(session, tokens);
var dbConnectionFactory = authService.TryResolve<IDbConnectionFactory>();
foreach (var authTokens in session.ProviderOAuthAccess)
{
if (authTokens.Provider.ToLower() == "github")
{
GithubProfileUrl = session.GetProfileUrl();
}
if (authTokens.Provider.ToLower() == "twitter")
{
TwitterProfileUrl = session.GetProfileUrl();
if (appSettings.GetList("TwitterAdmins").Contains(session.UserName)
&& !session.HasRole(RoleNames.Admin))
{
userAuthRepo.AssignRoles(userAuth, roles:new[]{RoleNames.Admin});
}
}
DefaultProfileUrl = GithubProfileUrl ?? TwitterProfileUrl;
using (var db = dbConnectionFactory.OpenDbConnection())
{
var userAuthInstance = db.Single<CustomUserAuth>(x =>
x.Id == this.UserAuthId.ToInt());
if (userAuthInstance != null)
{
userAuthInstance.DefaultProfileUrl = this.DefaultProfileUrl;
db.Save(userAuthInstance);
}
}
}
}
}
Which fetches the Profile Url of the User when they login via GitHub or Twitter. Will assign the Admin role to users in the TwitterAdmins AppSetting, which is a way to assign admin rights to known Twitter users. Finally the retrieved Profile Url is added to the CustomUserAuth POCO Table and saved.
TechStacks tells ServiceStack to use its own CustomUserAuth table instead by registering a generic OrmLiteAuthRepository:
var authRepo = new OrmLiteAuthRepository<CustomUserAuth, UserAuthDetails>(dbFactory);
container.Register<IUserAuthRepository>(authRepo);
authRepo.InitSchema();
Where it will now Save User Information in the CustomUserAuth instead of the default UserAuth table.
Related
I know by creating an user service with entity framework and creating a password hash i can add one or more users to the website! but i'd like to use asp.net identity features even when i want to register batch users (like upload users list with excel or xml file).
In my scenario i want register more than one users on the website by uploading users list in xml,json or excel file. And i want to register all of them in one transaction.
Has anyone idea?
Depends at what level of abstraction you want to work at, but by just looping over the content of the default Register method, you could do something like this:
[HttpPost]
public async Task<IActionResult> RegisterLotsOfPeople(RegisterLotsModel model)
{
var successful = new List<string>();
var failed = new List<string>();
foreach (var toRegister in model.ApplicationUsers)
{
var user = new ApplicationUser {UserName = toRegister.UserName, Email = toRegister.Email};
var result = await _userManager.CreateAsync(user, toRegister.Password);
if (result.Succeeded)
{
successful.Add(toRegister.UserName);
}
else
{
failed.Add(toRegister.UserName);
}
}
return Json(new {SuccessfullyRegistered = successful, FailedToRegister = failed});
}
You'd have to post the data to the end point in JSON format.
The DTO classes are:
public class RegisterLotsModel
{
public List<UserToRegister> ApplicationUsers { get; set; }
}
public class UserToRegister
{
public string UserName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
There's lots of other way to do what you're trying to achieve, but this is quick, dirty and would likely work fine. You may need to send the confirmation email in the success part of the method, if email confirmation is required.
Edit - Single Transaction
To insert all the new users in one transaction, you would have to generate their password hashes first, and then insert them into the database.
To get a hash of a given password, you can use the password hasher provided by the UserManager:
foreach (var toRegister in model.ApplicationUsers)
{
var hasher = _userManager.PasswordHasher;
var user = new ApplicationUser {UserName = toRegister.UserName, Email = toRegister.Email};
toRegister.Hashed = hasher.HashPassword(user, toRegister.Password);
}
You could then manually insert these into the database. This would be enough for basic password authentication, but if your implementation uses things like SecurityStamp, you would likely need to implement the appropriate methods when creating the user.
I'm trying to implement this architecture for the first time in a Winform. So I have a simple but very important question for me.
Take a simple example. I want the form to retrieve a user list and to allow a modification of the phone number.
I have this for the first step (simplified and I normally use interfaces)
public Form1()
{
InitializeComponent();
UserService _userService = new UserService();
listBoxUsers.DataSource = _userService.GetAllUsers();
}
class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
}
class UserService
{
UserRepository _userRepository=new UserRepository();
public Dictionary<int, string> GetAllUsers()
{
DataTable dtbl= _userRepository.AllUsers();
//Some code here
return dict;
}
}
class UserRepository
{
public DataTable AllUsers()
{
//Sql query
return dtbl;
}
}
Now by selecting a user in the lisbox, I'm able to display some information as the Phone number. When I'm changing the phone number, I need a method called UpdatePhoneNumber to update the SQL database.
But, where to place it? User or UserService (I don't talk about the SQL query, just the logic)
And after that, how to access (here or somewhere else in the app) to this user property to display it in the form? Directly with _user.Id (User must be instantiated in the form) or implement a _userService.The id which retrieves User.ID (in this case Form knows only UserService class).
Many thanks for your precious help
Put all Methods working on the User's data in the user class. Ask yourself the question what the user can do? Put all the logic which controlls the users in UserService like GetUserById, GetAllUsers, CreateUser and so..
Put all the method which the user can perform in the User class.
Or lately i was building such kind of thing and i merged User and UserServices into one and made the UserServices class method static so i can access them without instantion of the User.
Hope this help.
Here is what your basic 3-layered app looks like.
UI (your form and ui supporting objects)
BLL (GetAllUsers, SaveUser, DeleteUser, etc)
Data (ADO, EF, etc)
In your particular case, you really looking for Master-detail concept. A master usually the one where you display list of users
// Master
var _userList = Service.GetAllUsers(); // List<UserModel>
userGrid.Datasource = _userList;
I will not discuss it here but you can set bindings so that click on grid will result in detail control being populated. Or manually
// detail
UserModel model = master._userList[currIndex];
txtFirstName.Text = model.FirstName;
txtPhone.Text = model.Phone;
// . . . .
Now, of course, you're about to change the text box and save user...
// detail
UserModel model = master._userList[currIndex];
Service.SaveUser(model);
Master.Reload();
This is general idea, how this is done. If you follow, you have distinct layers. UI calls Service, which calls Data. For example, you have BLL
// Service
private IUserDataProvider _provider;
public List<UserModel> GetAllUsers()
{
var data = _provider.Get<User>();
// massage your 'data' and return List<UserModel>
. . . .
}
your provider might return some unwanted data, so you can use BLL to trim it and return only appropriate data. But you don't know what provider is doing inside. May be it is doing Ado.net or Entity Framework. Hence a true separation of layers.
I have a system where all pages (views) and all controls (buttons, links, menu itens ...) have security roles applied to them.
So I have an admin interface where all pages and controls are registered. And each user has a set of individual permissions.
So, for example:
I have a View EditCar, with 3 buttons: "New", "Delete" and "Back".
So the user X have permission to see View EditCar, and only the button "Back"
So each new view must be registered, and the users associated with. There is no roles, because each user is 100% configurable.
So, I have a FilterAttribute:
public class CustomAuthorize : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
var userPermissions = repository.GetAll().Where(x => x.Name.Equals(User.Identity.Name);
// if (!userPermissions.Pages.Any(x => x.NamePage.Contains(???))))
}
else
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
So my question is :
- What should I keep in database to identify each View(Action) ? Maybe 3 values? Area-Controller-Action?
Is it the best option? Any other idea about that solution?
Thanks
I have same scenario in my web-application and it is working in the following way:
we have in database:
Permission contains View, Add, Edit, Delete
Feature contains all the feature which can be set over role
FeaturePermission bind the feature with permission like which feature has what permisssion
UserRole has the role of a user
RoleFeaturePermission shows that which role has what permission to allowed
Now in code I do when a user authenticate I generate the list of permission assigned to it with features then I defined an Enum like:
public enum FeatureValue
{
Custom = 1,
Schedule = 2,
Export=3
}
public enum PermissionValue
{
View = 1,
Add = 2,
Edit = 3,
Delete = 4
}
and the UserPermission static class to get authorization:
public static bool VerifyPermission(FeatureValue feature, PermissionValue permission, int id) {
return getFeaturePermissionsForReport(feature, permission, id);
}
private static bool getFeaturePermissionsForReport(FeatureValue feature, PermissionValue permission, int id) {
SessionHelper sessionHelper = new SessionHelper(null);
UserModel userModel = sessionHelper .getUser()//get user from session.
if (userModel != null && userModel.IsAuthorized == false) return false;
UserProfile userProfile = sessionHelper.Get<UserProfile> ();
if (userProfile != null && userProfile.AssignedRoleList != null) {
List<Core.Entities.FeaturePermission> featurePermission = userProfile.AssignedRoleList.SelectMany(b => b.RoleFeaturePermission).ToList();
if (featurePermission != null) {
if (featurePermission.Count(f = > f.Feature.Id == (int) feature && f.Permission.Id == (int) permission) > 0) {
bool isAllowed= false;
int featurePermissionId = featurePermission.Where(f = > f.Feature.Id == (int) feature && f.Permission.Id == (int) permission).Select(i = > i.Id).FirstOrDefault();
isAllowed = (reports.Count(r = > (r.FeaturePermissionId == featurePermissionId && r.Id == id)) > 0) ? true : false;
return isAllowed;
}
}
}
return false;
}
and now one each link, button or action use:
#if (UserPermission.VerifyPermission(FeatureValue.Custom, PermissionValue.Edit))
{
//action link to edit custom view
}
and for action custom attribute is:
[AttributeUsage(AttributeTargets.All,AllowMultiple=true)]
public class CustomFeaturePermissionAttribute : ActionFilterAttribute
{
private FeatureValue[] feature;
private PermissionValue[] permission;
private bool excludeParamId;
/// <summary>
/// Set values of featurelist and permission list
/// </summary>
/// <param name="featureList"></param>
/// <param name="permissionList"></param>
public CustomFeaturePermissionAttribute(object featureList,object permissionList, int excludeParamId)
{
FeatureList = (FeatureValue[])featureList;
PermissionList = (PermissionValue[])permissionList;
ExcludeParamId = excludeParamId;
}
public FeatureValue[] FeatureList
{
get
{
return feature;
}
set
{
feature = value;
}
}
public bool ExcludeParamId
{
get
{
return excludeParamId;
}
set
{
excludeParamId = value;
}
}
public PermissionValue[] PermissionList
{
get
{
return permission;
}
set
{
permission = value;
}
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
bool isAccessAllowed = false;
FeatureValue feature;
PermissionValue permission;
for (int i = 0; i < FeatureList.Count(); i++)
{
feature = FeatureList[i];
permission = PermissionList[i];
isAccessAllowed = UserPermission.VerifyPermission(feature, permission, Convert.ToInt16(ExcludeParamId));
if (isAccessAllowed)
break;
}
if (!isAccessAllowed)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { action = "UnauthorizedAccess", controller = "Security" }));
}
}
}
and on actions allow role having view permission over Custom and Export:
[CustomFeaturePermission(new FeatureValue[] { FeatureValue.Custom, FeatureValue.Export }, new PermissionValue[] { PermissionValue.View, PermissionValue.View},pageId)]
public ActionResult Custom()
{
//action body
}
I would create an abstract way of defining each permission, such as an enum. For example:
public enum UserPermissions
{
ViewCars,
EditCars,
DeleteCars,
ViewUsers,
EditUsers,
DeleteUsers
}
You could create these in the database in a table called Permissions, then create a many-to-many mapping where each user can be assigned to any number of permissions.
Then you would create a custom authorization attribute by deriving from AuthorizeAttribute and override the OnAuthorization method to load the user from the database. This is exactly what you have done in your question except the key part is that you want to add some property where you can define the permission(s) needed for an action, like so:
public class UserPermissionsAttribute : AuthorizeAttribute
{
public IEnumerable<UserPermissions> PermissionsRequired { get; set; }
public UserPermissionsAttribute()
{
}
public UserPermissionsAttribute(params UserPermissions[] permissionsRequired)
{
PermissionsRequired = permissionsRequired;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
var user = filterContext.HttpContext.User; // get user from DB
if (PermissionsRequired.All(x => user.Permissions.Any(y => x == y)))
{
// all permissions are met
base.OnAuthorization(filterContext);
}
else
{
throw new UnauthorizedAccessException();
}
base.OnAuthorization(filterContext);
}
}
Now you can decorate each action or controller with a permission or list of permissions:
[UserPermissions(UserPermissions.ViewCars, UserPermissions.EditCars)]
public ActionResult Index()
{
ViewBag.Title = "Home Page";
return View();
}
This way you separate your permission system from MVC controller/action logic.
Although I'd advise against this method of storing each permission on an individual basis. The role system keeps things much simpler and will improve performance. I really think you could do this with a number of fine-grained roles instead of fine-grained permissions.
Note that Authorizing users to see specific page elements differs from Authorizing for CRUD or other database operations, unless the elements point to operational Actions in Controller. Consider that you may have some elements that there's no need to be saw by a specific user, and don't have specific database operation. Till now we conclude that we need the following permissions :
Permission to See
Permission to Command
I believe that you can use Microsoft Role Provider for both parts. According to MSDN Documentation Considering that :
The Authorize attribute lets you indicate that authorization is
restricted to predefined roles or to individual users. This gives you
a high degree of control over who is authorized to view any page on
the site.
In The next step/question is how to do that?
I think 3 ways are available to meet our purpose:
Solution 1: Creating separate Views with specific page elements due to forwarding each user to related View. In this scenario we must
create separate controller actions too. we have to check user types
before each action like [Authorise(Roles="Administrator")]. We
forced to have static (Pre-defined) Roles and Accessibility. And in
one sentence Not a good solution because of redundancy and
instability.
Solution 2: Creating pages Dynamically simply by adding some if conditions for each access restricted element in One Page(for
example Edit Page). That is like employing #if
(User.IsInRole("Admin")) to authorize specific users and show
related page elements like buttons. In Controller side we can use
if conditions (not as FilterAttribute due to add dynamic
functionality based on generated/added new roles) and control valid
transactions against database. Although FilterAttributes add some great functionalists (like performance optimization). In one sentence A moderate solution.
Solution 3: Act like solution 2, just fix Controller problem by
creating our own custom FilterAttribute for authorization. That will
inherited from AuthorizeAttribute and overrides the OnAuthorize
method to do what you need only for Operations.
For Example :
public class TableAuthorizeAttribute : AuthorizeAttribute
{
public enum TableAction
{
Read,
Create,
Update,
Delete
}
public TableAction Action { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
//do custom authorizization using Action and getting TableEntryID
//from filterContext.HttpContext.Request.QueryString or
//filterContext.HttpContext.Request.Form
}
}
And its usage will be like this :
[TableAuthorize(Action=TableAuthorizeAttribute.TableAction.Update)]
Here is complete example about above concept. Here is complete example for creating dynamic AuthorizeAttribute for authorizing new roles added to application.
Solution 3 in one sentence A perfect but Complex Solution.
Note that by using FilterAttribute before Actions we have limited our application to static/predefined roles. No need to use another Data Structure or generate tables in Database.
I've seen a similar implementation in the past which utilized a token concept.
Each Action method is represented by a token. A selection of tokens define a role. A role is assigned to a user.
I used a simple console application to reflect my MVC application and look for all Controllers and determine every action method within them.
Store these "Tokens" in your database along with your roles.
The implementation kept it simple and just used the fully qualified name with namespaces etc to identify them. This way the data has to be specific to your application which can increase security
I would take Trevor's approach, but It wouldn't use an attribute.
I would create a common action permission enum like :
[Flags]
internal enum PermissionsEnum
{
listbutton = 1,
editbutton = 2,
deletebutton = 4,
savebutton = 8,
createbutton = 16,
action03 = 32,
action04 = 64,
action05 = 128,
action06 = 256,
action07 = 512,
action08 = 1024,
action09 = 2048,
action10 = 4096,
action11 = 8192,
action12 = 16384,
action13 = 32768
}
Such a permission object I store for every area/controller and user in the database like with some additional constraints
permission value -1 not allowed to call the action and permission value 0 to call the action but no other permissions:
Controller/Action UserId Permission
================= ====== =========
cars/delete User0001 -1
cars/edit User0001 8
cars/index User0001 0
cars/list User0001 16
cars/show User0001 2
The apply the permissions I would create a base controller. When ever an action is called, the base controller retrieves the permissions for the called controller:
var currentController = this.Url.RouteData["controller"];
var currentAction = this.Url.RouteData["action"];
var currentUserPermissons = GetUserPermissonForController(string.Format("{0}/{1}",currentController,currentAction), userId);
if( 0 > currentUserPermissons ) RedirectToAction("PermissonDenied","Error");
ViewBag.UserPermissons = (PermissionsEnum)currentUserPermissons;
In each view I would check the ViewBag.UserPermissons before create a protected item like:
#{ if((ViewBag.UserPermissons & PermissionsEnum.listbutton) == PermissionsEnum.listbutton)
{
#Html.ActionLink("Listitems","List")
}
}
I don't have a lot of experience with this and I am really hoping to get a good suggestion from you guys. I need to implement the following security scenario and I would like to know the best way to do it.
Imagine we have Employees, Supervisors and Department managers.
Both Employees and Supervisors have ManagerId assigned based off and pointing to the department manager they belong to.
When a supervisor user logs in I want him to only see records for employees that belong to the same ManagerId as his.
If another supervisor with another ManagerId user logs in and manually punches other employee's information in url (ex: wwww.domain.com/employee/details/{id} ),
because his ManagerId != employee's ManagerId I would like the access to be restricted.
Does it make sense ?
I started typing out checks on all ActionMethods such as:
public ActionResult Details(int id)
{
var employee = employeeRepository.Get(id)
var user = (CustomIdentity)ControllerContext.HttpContext.User.Identity;
if(employee.managerId == user.managerId)
{
Do whatever...
}
else
{
Not allowed
}
}
But typing that out in all ActionMethods seems redundant and just..ehh... I know there must be a better way.
Here is a stab at a solution. It needs a bit of cleanup but should give you everything you need.
Create a custom ActionFilter, and then decorate your methods with it.
[ManagerIdAuthentication]
public ActionResult Details(int id)
{
// Gets executed if the filter allows it to go through.
}
The next class can be created in a separate library so you can include it in all your actions that require this validation.
public class ManagerIdAuthentication : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// the next line needs improvement, only works on an httpGet since retrieves
// the id from the url. Improve this line to obtain the id regardless of
// the method (GET, POST, etc.)
var id = filterContext.HttpContext.Request.QueryString["id"];
var employee = employeeRepository.Get(id);
var user = filterContext.HttpContext.User.Identity;
if (employee.managerId == user.managerId)
{
var res = filterContext.HttpContext.Response;
res.StatusCode = 402;
res.End();
filterContext.Result = new EmptyResult(); //may use content result if want to provide additional info in the error message.
}
else
{
// OK, let it through.
}
}
}
I had a similar issue in the past, what I would consider per-object permissions. What I did was add a member to the object similar to:
public bool CanUserAccess(User user) {
return managerId == user.managerId;
}
Then, at the top of each action providing access to a controlled resource:
public ActionResult Details(int id)
{
var employee = employeeRepository.Get(id)
var user = (CustomIdentity)ControllerContext.HttpContext.User.Identity;
if(!employee.CanUserAccess(user))
return new HttpUnauthorizedResult();
// Normal logic here
}
It's certainly not perfect, but it does centralize the permission handling and allows you to easily increase the complexity in the future (allow access up the chain, special rules for HR, etc.). You could also write another overload/extension to access the User.Identity property for a bit more automation (or at least handle the type conversions).
Since I was dealing with ACL's, I would have additional methods/parameters to specify the basic nature of the action (e.g. Read, Write, Delete, Create, etc.).
I'm trying to achieve the following:
When a user has been successfully authenticated, I need to create a Global user object which I can access from different Forms (or classes).
I was looking through the Data Sources available in VS, and saw there's a "Object" option which may be suitable for what I'm trying to achieve. The trouble is, I have no idea how it works.
Can anyone point me in the right direction?
Thanks.
Assuming that this is a Windows Forms application, you can create a User class that is stored in a static ApplicationState class.
Steps:
1) Create your user class to hold information about the user:
public class User
{
public string Login { get; set; }
//.. other properties
}
2) Create your ApplicationState class:
public static class ApplicationState
{
public static User CurrentUser { get; set; }
}
3) In your login process, create a new version of the user class and assign it to the ApplicationState.CurrentUser property:
public void CompleteLogin(string sLogin)
{
User user = new User();
user.Login = sLogin;
ApplicationState.CurrentUser = user;
}
4) You can now use ApplicationState.CurrentUser just about anywhere in your project.
It's called a Singleton, and it's a Bad Thing (especially when its state can be mutated). Investigate Dependency Injection (DI) instead. There's even a .NET-specific book on it.
Per request, here's a simple (probably oversimplified) example of doing DI manually. A DI Container library (also known as an Inversion of Control or IoC Container library) can simplify the process of "wiring everything up" in the composition root, and usually also provides lifetime management and other features.
// Composition root of your application
void Main()
{
// Only instance of user we will ever create
var user = new User();
var instance = new MyClass(user);
}
public interface IUser
{
string Name { get; set; }
}
public class User: IUser
{
public string Name { get; set; }
}
public class MyClass
{
public MyClass(IUser user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
_user = user;
}
private readonly IUser _user;
}
You could use or create a public List making sure that you only add the authenticated users to the List once they have been validated you could even do this via encapsulating field access, create a List or string[] property what you are asking you probably would want to create a class level Property.