I am using angularjs with Asp.net MVC to check the write access of a folder for users. If the user has the write access then I want to show a div which has a link. I have a div in SampleView.Html and I have a method which checks for user's write access in MVC Controller called ReportController.cs. What will be the code for Angular Controller that I can use to pass value from MVC controller to Angularjs View?
SampleView.html:
<div id="DivPackerTemplate" class="cp-btn cp-btn-primary pull-right">
<a ng-href="\\Samplefolder" >Edit Template</a></div>
ReportController.cs:
public void AccessPackerPlanTemplate(string folderPath)
{
string path = #"\\sample";
string NtAccountName = #"sampleuser";
DirectoryInfo di = new DirectoryInfo(path);
DirectorySecurity acl = di.GetAccessControl(AccessControlSections.All);
AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));
//Go through the rules returned from the DirectorySecurity
foreach (AuthorizationRule rule in rules)
{
//If we find one that matches the identity we are looking for
if (rule.IdentityReference.Value.Equals(NtAccountName, StringComparison.CurrentCultureIgnoreCase))
{
//Cast to a FileSystemAccessRule to check for access rights
if ((((FileSystemAccessRule)rule).FileSystemRights & FileSystemRights.WriteData) > 0)
{
//Show the link
{
DivPackerTemplate.Visible = false; \\This is not working is there a alternative for this?
}
}
}
}
I might not be understanding the question exactly correctly, but I you case it might be best just to show or hide it using razor syntax, rather than exposing a variable and handling that in the JavaScript. If you're not returning a Model from your ASP.NET controller, then in your ASP.NET controller set the ViewBag variable like this:
ViewBag.DivPackerTemplateVisible = false;
And in your view:
#if(ViewBag.DivPackerTemplateVisible) {
<div id="DivPackerTemplate" class="cp-btn cp-btn-primary pull-right"><a ng-href="\\Samplefolder" >Edit Template</a></div>
}
You should also make sure that ViewBag.DivPackerTemplateVisible always has a value of true or false, possibly by declaring it to true at the top of your ASP.NET controller.
Related
I have a website with two forms one for inHole and the other Surface. The forms are identical but I would like to know where did the user clicked so I can assign a value to my SureyLocationID in the controller so I can refer to it later in my database if I need to without creating 2 views. Is there a way of doing so?
You can use Query string to pass a parameter with your link like :
http://example.com/over/there?sureyLocationID=inHole
or
http://example.com/over/there?sureyLocationID=Surface
So you just have to check the URL and retrieve the information you pass through it
In your MVC view have a button or anchor tag like this:
<a href='#Url.Action("YOUR_ACTION_NAME", "YOUR_CONTROLLER_NAME", new { comingFromInHole = true } )'>NAME_FOR_THIS_ELEMENT</a>
or
<input type="button"
onclick="location.href='#Url.Action("YOUR_ACTION_NAME", "YOUR_CONTROLLER_NAME", new { comingFromInHole = true} )'"
value="NAME_FOR_THIS_ELEMENT"/>
And in you MVC Controller:
public IActionResult YOUR_ACTION_NAME(bool comingFromInHole)
{
if (comingFromInHole)
{
// logic related coming from hole
}
else
{
// Logic related to surface
}
}
If you don't want to use boolean true or false, then you could use enumeration (or your custom defined type..etc) and use that as well:
public enum Types {InHole, Surface };
Then controller action signature will be changed to take in Types enum
public IActionResult YOUR_ACTION_NAME(Types type)
and modify your button or anchor link to send enum type to controller as below:
<a href='#Url.Action("YOUR_ACTION_NAME", "YOUR_CONTROLLER_NAME", new { Types=HomeController.Types.InHole} )'>NAME_FOR_THIS_ELEMENT</a>
I am using angularjs with Asp.net MVC to check the write access of a folder for users. If the user has the write access then I want to show a div which has a link. I have a Div in SampleView.Html and I have a method which checks for user's write access in MVC Controller called ReportController.cs. what will be the code for Angular Controller that I can use to pass value from MVC controller to Angularjs View?
SampleView.html:
<div id="DivPackerTemplate" class="cp-btn cp-btn-primary pull-right"><a ng-href="\\Samplefolder" >Edit Template</a></div>
ReportController.cs:
public void AccessPackerPlanTemplate(string folderPath)
{
string path = #"\\sample";
string NtAccountName = #"sampleuser";
DirectoryInfo di = new DirectoryInfo(path);
DirectorySecurity acl = di.GetAccessControl(AccessControlSections.All);
AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));
//Go through the rules returned from the DirectorySecurity
foreach (AuthorizationRule rule in rules)
{
//If we find one that matches the identity we are looking for
if (rule.IdentityReference.Value.Equals(NtAccountName, StringComparison.CurrentCultureIgnoreCase))
{
//Cast to a FileSystemAccessRule to check for access rights
if ((((FileSystemAccessRule)rule).FileSystemRights & FileSystemRights.WriteData) > 0)
{
//Show the link
{
DivPackerTemplate.Visible = false; \\This is not working is there a alternative for this?
}
}
}
}
If your using angular you should make SampleView.Html a directive and inject a service that can call your mvc AccessPackerPlanTemplate method to get the information or better yet create an angular rule service that can wrap and all your rule logic and cache results.
Step 1: create the directive to wrap DivPackerTemplate
Directive doc -> https://docs.angularjs.org/guide/directive
Step 2: create an angular service that wraps your calls to rules logic (rules should be in webapi but you can use regular mvc actions if you must) -> https://docs.angularjs.org/guide/services
Then you simply wire them up by injecting your rules service into the directive and using it to populate the template data, caching is optional.
In the angular world you do not "pass value's" from the server into a view, your views use angular services to "pull values" into views/directives
I'm not an angular expert but something along these lines, omitted the rules service implementation ($rules) as angular services are fairly easy to create.
angular.module('moduleA', [])
.controller('SimpleDirectiveController', ['$rules','$scope',function($rules,$scope) {
$scope.show = function() {
return $rules.yourmethodtogetrulesresult();//for this case return either 'hidden' or 'visible'
}; }])
.directive('PackerTemplate', function() {
return {
template: function($scope) {
var templatevar = '<a ng-href="\\Samplefolder" visibility=\'[XX]\'>Edit Template</a>'
return templatevar.replace('[XX]',$scope.show())
}
};
});
From your MVC application you can return an asp view. Inside the view you can use your angular controller like this:
#model dynamic
#{
Layout = "";
}
<div ng-controller="PackerListController as vm">
<h1 class="page-header">
<button ng-click="vm.editTemplate()">Edit Template</button>
</h1>
</div>
My View uses #Html.Action(…) to reflect various functional blocks. In opening the page, the site shows Authorization dialog box for users that do not have role pointed in controller method. (e.g. “manager” or “caller”) On pressing “cancel” get:
401 - Unauthorized: Access is denied due to invalid credentials.
May I achieve changes of my application behavior in case a user has no required roles, #Html.Action is ignored or nothing is shown?
My VIew:
#model InApp.ViewModel.ListViewModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="CallList">
#Html.Action("List","Call",new {id=Model.id})
</div>
<div class="Order">
#Html.Action("Create","Order",new {id=Model.id})
</div>
Controllers:
[Authorize(Roles = "manager, caller")] //if a user is not 'manager' or 'caller'
public PartialViewResult List() // nothing is shown
{
//...private
return PartialView();
}
[Authorize(Roles = "manager, admin")]
public PartialViewResultCreate()
{
//...private
return PartialView();
}
Trying to find the correct solution I have found similar questions:
Ignore #Html.Action() if user not in Role
and asp.net MVC3 razor: display actionlink based on user role
But I do not like “if” condition in my View. I am looking for a complex solution to hide and show separate parts using only AuthorizeAttribute and to avoid if – else in View or Controller. Thanks for any help!
I can suggest using this extension method:
This is a wrapper for #Html.Action which checks the user rights by using reflection.
public static MvcHtmlString ActionBaseRole(this HtmlHelper value, string actionName, string controllerName, object routeValues , IPrincipal user)
{
bool userHasRequeredRole = false;
Type t = Type.GetType((string.Format("MyProject.Controllers.{0}Controller",controllerName))); // MyProject.Controllers... replace on you namespace
MethodInfo method = t.GetMethod(actionName);
var attr = (method.GetCustomAttribute(typeof(AuthorizeAttribute), true) as AuthorizeAttribute);
if (attr != null)
{
string[] methodRequeredRoles = attr.Roles.Split(',');
userHasRequeredRole = methodRequeredRoles.Any(r => user.IsInRole(r.Trim())); // user roles check in depends on implementation authorization in you site
// In a simple version that might look like
}
else userHasRequeredRole = true; //method don't have Authorize Attribute
return userHasRequeredRole ? value.Action(actionName, controllerName, routeValues) : MvcHtmlString.Empty;
}
Using in view:
#Html.ActionBaseRole("List","Call",new {id=Model.id},User)
If you do not like this logic in the view - move it somewhere else. For example you can make your own extension method and use it like #Html.ActionOrNothing(...).
And the implementation should check if user has permissing to view something and return an empty string/view otherwise.
I am trying to build a dynamic menu for my ASP.NET MVC4 web application. As I am constructing the menu I want to make sure that menu items for which a user should not have access are not displayed in the menu.
I am using forms authentication and the [Authorize] attribute with each page requiring a given a role.
Given two strings (Controller and Action), and a logged in user, how can I determine if a user will have access to that Controller Action?
All of my menu data is stored in a database. My plan to render the menu is to construct a JSON object of the menu data and embed that into the View. Then client side I will use Handlebars.js and plug the menu JSON object into a template.
What I am trying to do is check permissions on a given Controller/Action for a user as I am rendering the menu data. My initial thought was to use reflection and look up the controller action method and check for the existence of an Authorize attribute and check to see if the current logged in user has the necessary role access that page. If not, then the menu item would not be rendered.
I am always reluctant to use reflection however, there usually tends to be an easier way of doing things.
public static IEnumerable<MethodInfo> GetActions(string controller, string action)
{
return Assembly.GetExecutingAssembly().GetTypes()
.Where(t =>(t.Name == controller && typeof(Controller).IsAssignableFrom(t)))
.SelectMany(
type =>
type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(a => a.Name == action && a.ReturnType == typeof(ActionResult))
);
}
then
var roles = ((AuthorizeAttribute) (GetActions("ControllerName" + "Controller", "ActionName").First().GetCustomAttributes(typeof (AuthorizeAttribute), false)[0])).Roles;
if(roles.Contains("admin or smth"))
{
doSomsing();
}
I have implemented a very similar scenario.
The only difference is that my menus are stored in XML files.
Since you have your menu data stored in a database, I suggest you either add an xml field that contains security info to each menu record; or, have a new table that maps menu items to users.
The table can look like this:
MenuItemName (id) User
---------------------------------------
ViewVacationHistory (12) firstuser
ViewVacationHistory (12) seconduser
ApproveVacationRequest (10) seconduser
Now when your controller receives the request that would result in displaying menu items, and since your controller is decorated with the Authorize attribute, it will receive the user in the HttpContext. Here you simply query the database for menu items that match, then render the menu accordingly.
Use ActionFilter Attribute to filter the users based on Role
http://www.asp.net/mvc/tutorials/hands-on-labs/aspnet-mvc-4-custom-action-filters
create the class called Rolevalidation and add the code as below
public class AuthorizeRoles : AuthorizeAttribute
{
List<string> roles = new List<string>(“your list of roles”);
bool isAuthenticated = false;
for (int i = 0; i < roles.Count(); i++)
{
if (u.Role.Name == roles[i])
{
isAuthenticated = true;
break;
}
}
if (isAuthenticated)
{
SetCachePolicy(filterContext);
}
else
{
filterContext.Result = new RedirectResult("~/Error");
}
}
Add this code in every controller’s begining* [AuthorizeRoles(Roles = "SuperAdmin")]
Assuming you have a view that contains all the menu html code, probably will be better just using:
<ul class="menu">
<li>
#Html.ActionLink("Home", "Index", "Home")
</li>
#if (System.Web.Security.Roles.IsUserInRole(User.Identity.Name, "Administrator"))
{
<li>
#Html.ActionLink("Statistics", "Index", "Stats")
</li>
}
</ul>
Hope this helps!
The links will be generated by the json object which comes from an action and controller.
The json object should have a list of links(or what ever required to implement the menu item), the list should be generated by sort of settings stored in the database, tells each user what links to show.
Beside that what if the user has the URL so in this case you need to use
https://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.users(v=vs.118).aspx
You can use an Authorize attribute with which to decorate an action from the controller [Authorize(AuthorizationContext)] or you can extend the authorize attribute for custom authorization;
You can also define some conventions in a dictionary in which you define that a Create action of a controller needs a create type authorization a.s.o.
Dictionary<string, Right> actionConventions = new Dictionary<string, Right>
{
{ "Index", Right.View },
{ "List", Right.View },
{ "Open", Right.View },
{ "Create", Right.Create},
{ "Edit", Right.Edit },
{ "Delete", Right.Delete }
}
and override OnAuthorization and Authorize methods of AuthorizeAttribute and either check the convention if the action sticks to the conventions defined in the dictionary or check a specific condition where you either Authorize(AuthorizationContext) for the action or HandleUnauthorizedRequest(AuthorizationContext).
Handling the menu you can create an authorization service in which you return the rights of the current user and add a class containing the rights of the user and you check the Model when rendering the model, if a menu item should be rendered or not.
Authorize Attribute MSDN
I'm a web developer new to using the MVC3 framework. We're building a site that implements a lot of sub folders for different segments of our audience. This routing concept is throwing a wrench in our structure for SEO.
In my global.asax file under the routing section we have:
routes.MapRoute("test", "test/{testFirst}/{testSecond}",
new { controller = "test", action = "RouteTest", testSecond = UrlParameter.Optional });
and in my controller we have:
public ActionResult RouteTest(string testFirst, string testSecond)
{
return View(testFirst, testSecond);
}
When I run the site and try to go to /test/test/index it won't pull up the view. It's stuck looking for test.cshtml which doesn't exist because it's a folder not a file.
Any ideas on to how make nested folders work?
EDIT:
Here's a branch of the structure we want and maybe it will help with what I'm trying to accomplish.
This is kind of hard to show but it should get the idea across. We have 5 different audiences that come to the site. I broke down 1 audience and what the flow of that audience is.
Not all segments will have products some are just content other segments have that 3rd level and have products to view
audience
segment
segment
products
segment
products
segment
This is the basic structure that we want the URLs to take
domain.com/audience/segment/products/(productsname)
Suggestions on how to make this possible
You are using the wrong overload for the View() method. Here's what you're using when you call View(testFirst, testSecond):
protected internal ViewResult View(
string viewName,
string masterName
)
MSDN Reference.
By putting "test" for the viewName, you're telling the Controller to render a View called Test (test.cshtml). Which you don't have.
It sounds to me like you are trying to correlate WebForms with MVC. It is not the same, and you are seeing a prime example with routing. ASP.NET MVC doesn't work off of the NTFS structure (folders and files). It relies on routing through route definitions.
If you are looking to render the View "RouteTest", then do something like this:
public ActionResult RouteTest(string testFirst, string testSecond)
{
ViewBag.testFirst = testFirst;
ViewBag.testSecond = testSecond;
return View();
}
This will render the "RouteTest" view and in your dynamic object ViewBag you will have access to two properties: testFirst and testSecond. In your view you can pull those values. (Although I highly recommend strongly-typed Views using a ViewModel)
Example Solution
ViewModel
public class TestData
{
public string testFirst { get ; set ; }
public string testSecond { get ; set ; }
}
Controller
public ActionResult RouteTest(string testFirst, string testSecond)
{
TestData td = new TestData();
td.testFirst = testFirst;
td.testSecond = testSecond;
return View(td);
}
Strongly-Typed View
#model TestData
#Html.Label(Model.testFirst)
#Html.Label(Model.testSecond)