MVC3 Extra role attribute - asp.net

I'm creating a website where an Admin can add Teachers and Students, the admin should be able to specify what the Teacher can do when he's in a particular Location.
Is it possible to extend the Authorize attribute to check in what Location the specific user is in? for example [Authorize(Roles = "Administrator", Location="ICT")] ?
And if so, how can I extend this?
Thanks in advance.

And if so, how can I extend this?
By writing a custom authorize attribute:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public string Location { get; set; }
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
var result = base.AuthorizeCore(httpContext);
if (!result)
{
return false;
}
// At this stage we know that the currently logged in user
// is authorized. Now you could use the Location property
// to perform additional custom authorization checks and
// return true or false from here
string user = httpContext.User.Identity.Name;
...
}
}
and then:
[MyAuthorize(Roles = "Administrator", Location = "ICT")]

You can create Your own custom authorize attribute.
See video here asp-net-mvc3-custom-membership-authorizeattribute-tutorial

Related

How to force update custom user claims?

I've got a custom claim added to my ApplicationUser class as follows:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
if(Theme != null)
userIdentity.AddClaim(new Claim("ThemeBundle", Theme.Bundle));
return userIdentity;
}
public int? ThemeId { get; set; }
[ForeignKey("ThemeId")]
public virtual Theme Theme { get; set; }
}
I extended Identity like this:
public static class IdentityExtensions
{
public static string GetThemeBundle(this IIdentity identity)
{
var claim = ((ClaimsIdentity) identity).FindFirst("ThemeBundle");
// Test for null to avoid issues during testing
return (claim != null) ? claim.Value : string.Empty;
}
}
I update the model behind the claim from the following Action Method:
public ActionResult ChangeTheme(int id)
{
var theme = _db.Themes.Find(id);
if (theme == null)
return HttpNotFound();
var userId = User.Identity.GetUserId();
var user = _db.Users.Find(userId);
user.Theme = theme;
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
I access it in a view (or elsewhere) like this:
User.Identity.GetThemeBundle()
When the user updates their "Theme" property with the "ChangeTheme" action, nothing happens until they log off and log back in.
I've spent all day mulling over more than the following QA's with no good result:
Update User Claim not Taking Effect. Why?
MVC 5 AddToRole requires logout before it works?
And thanks to #Brendan Green: ASP.NET Identity - Forcing a re-login with security stamp
So far the best I've got is that the page will refresh and the claim returns an empty string instead of the desired result, OR I redirect the user to the login screen. At least those are less ambiguous than nothing happening.
How on earth can I get the claim to update globally as soon as the user changes their "Theme" property? I'd settle for a good way to fully log the user off and back on if needed. Using the AuthenticationManager.Signout and .Signin methods doesn't quite do the trick.
As of Asp.Net MVC 6 and Asp.Identity 3.0.0-rc1-final you could use Task SignInManager<TUser>.RefreshSignInAsync(TUser user); in order to do that.

getting Roles that already set to custom Authorization attribute?

I customized the authorize attribute of Asp.Net but I do not know how to get the roles which I set to the attribute when I set the attribute to a method or class
For example I have this CustomeAuthorizeAttribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CustomeAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (HttpContext.Current.User.Identity.IsAuthenticated && HttpContext.Current.User.IsInRole("Super"))
{
return true;
}
else
return false;
}
}
but I do not know how to get the roles when I set them to the attribute like this
[CustomeAuthorizeAttribute(Roles="admin,super-admin")]
by default it inhirits the Roles property from the base Authorize class so you can get the roles directly by using the Roles property
For Example
if (HttpContext.Current.User.Identity.IsAuthenticated && HttpContext.Current.User.IsInRole(Roles))
{
return true;
}
or you create new properties belong to your custom Authorization attribute and use them.

AuthorizeAttribute Redirect After user Login

I am using default Web Application template for MVC4 in Visual Studio. How can I write Authorize Attribute to redirect user after succesfull login? This attribute should look like this: [UserRedirect("username")] whether anyone use "username" login redirect should be made. Where do I apply this attribute? To the login page or index? Thanks for answer.
You need to override OnAuthorization method of AuthorizeAtribute
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class UserRedirectAttribute: AuthorizeAttribute
{
public string UserName{ get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.onAuthorization(filterContext);
if(base.AuthorizeCore(filterContext.HttpContext) == true)
{
//here put all the a logic for redirect condition ()
if(filterContext.HttpContext.User.Identity.Name.Equals(this.UserName,StringComparer.Ordinal)
{
//if you should do the redirect
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
controller = "Redirect controller name",
action = "Redirect action name"
})
);
}
}
}
}
Regarding the usage:
If it is an authorize attribute that is going to replace default authorize attribute you should on any authorized Action/Controller
EDIT:
Based on your last comment you don't have to use an attribute at all. Just add the redirect logic at the end of your login action:
[HttpPost]
public ActionResult Login(LoginModel model)
{
bool userAuthenticationResult = // here goes your authentication logic
if(userAuthenticationResult && HttpContext.User.Identity.Name.Equals(this.UserName,StringComparer.Ordinal))
{
//setup cookie/token any other things you need for the authentication to work
return RedirectToAction("ActionName","ControllerName");
}
}

How to make sure that only the user who created a post in a blog can delete or edit it asp .net MVC3?

How can I make sure that only the user who created a post in a blog can delete or edit it?
I.e. A user can create a blog post and can edit it at /post/edit/{ID}. What if a user changes the id to some other different value to a post which doesn't belong to him?
How to make sure that the post which he will edit belongs to him only?
You could write a custom Authorize attribute in which you will query your database to ensure that the currently connected user is the author of the blog post that he is trying to modify:
public class EnsureAuthorOfBlogAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
return false;
}
string blogId = httpContext.Request.RequestContext.RouteData.Values["id"] as string;
string username = httpContext.User.Identity.Name;
return IsBlogAuthor(username, blogId);
}
private bool IsBlogAuthor(string username, string blogId)
{
// TODO: you know what to do here
throw new NotImplementedException();
}
}
and then decorate the controller action with this custom attribute:
[HttpDelete]
[EnsureAuthorOfBlog]
public ActionResult Delete(int id)
{
...
}
and same for editing:
[HttpPut]
[EnsureAuthorOfBlog]
public ActionResult Update(BlogViewModel blog)
{
...
}

ASP.NET MVC3: custom [authorise] attribute

In my database, the system user has a list of modules he/she can access.
I would like to be able to add an authorise attribute which checks that this is the case.
E.g. [authorise(UserID, ControllerName)]
Which goes to some code, ensures that the User with UserID specified, has the controller name in his/her list.
At the moment you can simply bypass the fact the tabs aren't visible, by using the URL. (I have code which already checks if the user has specified access and hides/shows tabs)
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
return false;
}
string currentUser = httpContext.User.Identity.Name;
string currentController = httpContext.Request.RequestContext.RouteData.GetRequiredString("controller");
// TODO: go hit your database and see if currentUser can access
// currentController and return true/false from here
...
}
}
then decorate your controllers or actions:
[MyAuthorize]
public class FooController: Controller
{
...
}
This being said I suspect that you might have gone the wrong way in your database design by storing a list of which user has access to access which controller action. Probably you should have used roles for that. Having the database know about controllers just feels wrong.
So:
[Authorize(Roles = "Foo,Bar")]
public class FooController: Controller
{
...
}
Only users that have the Foo or Bar role can access the FooController.
You can create a new attribute.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class CustomAuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
bool authorized = // Perform custom logic
If(!authorized)
{
filterContext.Result = new RedirectResult(/* Your access denied url */);
}
}
}
When you create the model, check the permission
DisplayAdminLink = _permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel),
and in the view
#if (Model.DisplayAdminLink)
{
<li>#T("Account.Administration")
</li>
}

Resources