MVC4 Hiding links with a custom AuthorizeAttribute - c#

I've been digging around for a while now trying to figure out how to use my custom AuthorizeAttribute class in my view to show and hide links. I'm transitioning from IsInRole to the custom AuthorizeAttribute because I want the end user to select which groups are authorized to perform certain tasks. Up to this point I've been using:
#{ if (HttpContext.Current.User.IsInRole("UserMgr"))
{ Html.ActionLink("Edit", "Edit", new { id = item.pkRecID }); }
}
Where UserMgr is a domain group. (this does work but is not what I need to do)
I then created a custom AuthorizeAttribute class:
public class isAuthorized : AuthorizeAttribute
{
public string Access { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
string[] aszList = Access.Split(',');
if (!authorized)
{
// The user is not authenticated
return false;
}
var user = httpContext.User;
if (user.IsInRole("Admin"))
return true;
var rd = httpContext.Request.RequestContext.RouteData;
var id = rd.Values["id"] as string;
if (string.IsNullOrEmpty(id))
{
// Now id was specified => we do not allow access
return false;
}
foreach (string szGroup in aszList) // check to see if user is in group
{
if (user.IsInRole(szGroup))
{
return true;
}
}
return false;
}
This works in my controller to block access to functions but how do I hide links in my views using this function?
Thanks!

You could create an extension method, so you can apply it on the MvcHtmlStrings in your Cshtml file
Example:
public static IHtmlString If(this IHtmlString value, bool evaluation)
{
return evaluation ? value : MvcHtmlString.Empty;
}
Then on your html Element you can use it like this:
#Html.ActionLink("Reports", "Index", "Report").If(User.IsInRole("SuperAdmin"))
UPDATE
Steps:
Create a new static class in your project.
Add the suggested extension method to the newly created class.
To make this static class available in all cshtml views go to the webconfig located in the Views folder.
Again pay attention so that the web config is in the views folder, do NOT edit the one thats at the root of your app.
There add the namespace where your static class is located just like in the example below.
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="YourApplication.Utils"/> <!-- THIS IS THE EXAMPLE ON HOW TO INSERT THE NAMESPACE THAT CONTAINS YOUR STATIC CLASS -->
<add namespace="Microsoft.Web.Helpers"/>
</namespaces>
</pages>
</system.web.webPages.razor>
I cant explain it better then this.

Related

Is there any way add extension methods to razor PageModel?

Working on .Net core razor page. I want share some common methods among RazorPages (ex: HomeModel.cs).
Wrote below extension method
public static class PageModelExtension
{
public static string RemoteIpAddress(this PageModel pageModel)
{
return pageModel.Request.HttpContext.Connection.RemoteIpAddress.ToString();
}
}
Not sure how to access in Page Model like below.
public class HomeModel : PageModel
{
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
// .... some code
var ip = this.RemoteIpAddress(); // I want to use 'RemoteIpAddress' here
return Page();
}
}
Please help. Thanks
You use the ViewImports file to bring a namespace into scope in all Razor Pages.
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace WebApplication1.Extensions
{
public static class PageModelExtension
{
public static string RemoteIpAddress(this PageModel pageModel)
{
return pageModel.Request.HttpContext.Connection.RemoteIpAddress.ToString();
}
}
}
Then in the ViewImports file:
#using WebApplication1.Extensions
Then in your .cshtml file:
#{
var ip = this.RemoteIpAddress();
}
If you want to access it in the PageModel class itself, add a using directive for the namespace containing your extension method and then use this.RemoteIpAddress()
More about the ViewImports file in Razor Pages here
namespace MyDll.MyNamespace
{
public static class PageModelExtension
{
public static string RemoteIpAddress(this PageModel pageModel)
{
return pageModel.Request.HttpContext.Connection.RemoteIpAddress.ToString();
}
}
}
Go to the View's web.config and add the namespace to the path system.web/pages/namespaces:
<system.web>
...
<pages>
<namespaces>
....
<add namespace="MyDll.MyNamespace" />
</namespaces>
</pages>
</system.web>

Programmatically change the page redirection in web config

Hi i want to change the Page redirection in webconfig programmatically.
i have following code in web config.
<location path="WebForm2.aspx">
<system.webServer>
<httpRedirect enabled="true" destination="http://google.com" httpResponseStatus="Permanent" />
</system.webServer>
</location>
i want to enable or disable the httpredirect programmatically using c#.
please suggest me how to do this.
I've tried the code suggested by Rahul but I wasn't able to change the <location> element of the Web.config programatically.
As an alternative you could write an HttpHandler to intercept the request to the WebForm2.aspx page and redirect the user to another URL:
Handler:
namespace StackOverflowHelp
{
public class RedirectHandler : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
Uri uri = context.Request.Url;
if (uri.AbsolutePath == "/WebForm2.aspx.aspx")
context.Response.Redirect("http://google.com");
}
}
}
Handler registration in the Web.config:
<system.webServer>
<handlers>
<add verb="*" path="WebForm2.aspx"
name="RedirectHandler"
type="StackOverflowHelp.RedirectHandler"/>
</handlers>

IRouteHandler not routing through RouteConfig

I have a IRouteHander class which I use to resize images on the fly and add expire headers to them, Recently I moved to MVC5 and now updating my code. I tried to register the same route for that class in RouteConfig.cs
routes.Add(new Route("Image/{w}/{h}/{src}", new ThumbImageRouteHandler()));
but this route isn't working anymore like it was on MVC3 and giving 404 error in MVC5. Is there anything I am missing here? this route leads to
public class ThumbImageRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
HttpHanler httpHandler = new HttpHanler();
return httpHandler;
}
public class HttpHanler : IHttpHandler
{
public bool IsReusable
{
get
{
return false;
}
}
public void ProcessRequest(HttpContext context)
{
//Do something
}
}
}
}
Please help me fixing this issue. Thanks
After research I found out that I need to add a line in webconfig in order to make it work, here's how.
<system.webServer>
<handlers>
<add name="ApiURIs-ISAPI-Integrated-4.0-Image" path="/Image/*" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Because IRouteHandler is generating re-sized images with a dynamic path, and IIS thinks this is the actual path to a directory because of dot(.) in the link and it thinks it's an extension, which is actually not. So we have to add a handler in Web.Config to make it work.

Custom Role Provider not working - Instant redirect to login page after logging in

I have made a custom Role Provider. Before I updated my VS and NuGet packages everything seemed to work. However, when I login now it looks like the pages gets refreshed (or the View is reloaded atleast). I do see a cookie is created though, but I will not get redirect to Index. Why?
In my Web.Config:
<authentication mode="Forms">
<forms loginUrl="~/Home/Login" timeout="2880" />
</authentication>
<roleManager defaultProvider="MyRoleProvider">
<providers>
<add name="MyRoleProvider" type="project.Authorisation.CustomRoleProvider" />
<remove name="MySQLRoleProvider" />
<add name="MySQLRoleProvider" type="MySql.Web.Security.MySQLRoleProvider, MySql.Web, Version=6.9.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" connectionStringName="LocalMySqlServer" applicationName="/" />
</providers>
</roleManager>
In my HomeController:
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(User user)
{
if (ModelState.IsValid)
{
bool authenticated = userDBController.isAuthorized(user.Nickname, user.Password);
if (authenticated)
{
FormsAuthentication.SetAuthCookie(user.Nickname, false);
return Redirect(Url.Action("Index", "Home"));
}
else
{
ViewBag.Message = "Inlog data is incorrect!";
return View();
}
}
else
{
return View();
}
}
[Authorize(Roles = "ADMIN")]
public ActionResult Index()
{
return View();
}
So when I logged in I cannot go to Home/Index, it will redirect me to Login anyways. Same for after logging in.
My Custom RoleProvider is quite simple right now:
public class CustomRoleProvider : RoleProvider
{
private MainController mainController = MainController.Instance;
private UserDBController userDBController = MainController.Instance.GetUserDBController();
public override string[] GetRolesForUser(string username)
{
return userDBController.getRollen(username);
}
Before everything, this all worked (also the authorization).
Well I finally found out what was the issue!
Appearently after reinstalling packages and what not my web.config was changed. All I had to do is add enabled="true" to the roleManager section. Therefore the code should look like:
<roleManager defaultProvider="MyRoleProvider" enabled="true">
<providers>
<add name="MyRoleProvider" type="project.Authorisation.CustomRoleProvider" />
</providers>
</roleManager>
So appearently the rolemanager is disabled.
I hope this will help other people who might experience this problem!

Redirect page in web.config for a certain exception thrown

I have a MVC solution, which works with authorization for certain URLs based on the logged-in user.
I had managed this problem by using a protected method on the parent controller which checks if a user is administrator or not. This is the code:
[Authorize]
public abstract class ConfigurationController<E> : Controller where E : IPersistentVM, new()
{
//SOME OTHER CODE RIGHT HERE
protected ActionResult CheckPermission(string url, SPDCSS.Model.Rules.Enums.Permission.Permissions permission)
{
var user = Helper.GetLoggedInUser();
if (user.UserTypeId == (int)SPDCSS.Model.Rules.Enums.UserType.UserTypes.Administrator)
{
return View(url);
}
throw new UnauthorizedAccessException("Access Denied.");
}
}
And then, each inherited class calls this method this way:
namespace SPDCSS.Management.Web.Application.Controllers.Configuration
{
public class ChartController : ConfigurationController<ChartVM>
{
public ActionResult Chart()
{
return CheckPermission("~/Views/Configuration/Chart.cshtml",M.Enums.Permission.Permissions.Chart);
}
//MORE CODE HERE...
}
}
The problem is that I want to redirect for a specific view when I throw this exception, and I saw that most of people do it in the web.config file. I did it this way, but is not working:
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="~/Views/Shared/Error.cshtml">
<error statusCode="403" redirect="~/Views/Shared/UnauthorizedAccess.cshtml" />
</customErrors>
<!-- # some other code # -->
</system.web>
I think that maybe, the problem is on the status code which I had specified, but I don't what to use there. Any ideas about where the problem is?

Categories