I make security system in mvc application. In MVC it must be done by AuthorizeAttribute and roles string via actions methods.
Could i make this stuff: instead of action resolve I want to make view where html parts are hidden depend on current user permission set (For example: save button are not visible if user not Administrator).
Within your views, you can do conditional checks, such as:
<% if (User.IsInRole("Admin")) { %>
An Admin-only link
<% } %>
In partial views, the User property is not exposed, but you can still do it:
<% var user = HttpContext.Current.User; %>
<% if (user.IsInRole("Admin")) { %>
An Admin-only link
<% } %>
Brian - i don't think this is a good idea to 'hide' the admin parts. you basically then just expose to logic to anyone opening the html in 'view source' mode. it would be better to have an admin view and a 'normal' view and just do a case statement in the contoller action to deliver the appropriate view where required (still not the best option, but far better than hiding fields). better still, have a master view that contains partialviews which are only rendered if it's the correct user type etc..
just my 'view' on the topic..
jim
You can do either A or B
a) Create partial views for the various elements that change and do something like
<% if (HttpContext.Current.User.IsInRole("Administrator"))
{
Html.RenderPartial("AdminStuff");
}
else
{
Html.RenderPartial("RegularStuff");
}
%>
b) Set the role in your viewdata/viewmodel and use it in the code (not recommended as the view should really contain no logic)
In the controller
ViewData["Admin"] = HttpContext.Current.User.IsInRole("Administrator");
In the view
<% if ((bool)ViewData["Admin"]) { %>
<!-- Show admin stuff -->
<% } %>
Thanks to all for your answers. I see that view dynamic render is a bad practic in mvc applications. I'm used to think that there can be some libraries or templates.
BTW When i told to my PM that a string with roles is a common pattern he sad "Hard code!!!!". Now I'm designing some WCF service with will be an "Aplication Authoriser" ))).
Everyone here seems to forget that there is css for such stuff. You can do the thing you want very easily, at least I am doing at already, and it's working flawlessly.
Let me give you a simple example
Make sure your operations buttons/regions have defined css classes
css class: MODULE-OPERATION
e.g.
Module User
Operations: Add, Edit, Delete, List
Add User
Whenever changing (adding/updating/deleting) roles, you generate a css file for each role
e.g.
You decide that only administrators can add users so this css is generated
//admin_css.css
.USER-ADD { display: none; }
Everytime the page is opened you check what role the user has, and based on the role, you load the css file in you header. So your gui correlates to the logic you have in your application without so much hassle.
Related
I'm new to express JS and try to build CMS like this:
Users have a page builder, where they can drag-and-drop different components on the page.
each component has its own data which also is defined by a user
Each component has its own view template
So, I have to check what components have to load, prepare data for each of them, send this data to an appropriate template, render one big HTML and send to the client.
I know, It's too complicated to explain how to build this, but any tutorials, examples, resources would be appreciated.
IIUC, you can accomplish this using the include function that most template languages have. For the example, I'll use ejs. Also, I'm assuming you know how to get the data for user selections to your server.
on your app.js:
app.get('/someRoute', function(req, res) {
var data = //get user data here
res.render('someTemplate', {data:data});
});
someTemplate.ejs:
<%- include('header') %> //you should do this on every page
<% if (data == 'foo') { %>
<%- include('foo', {data:data}) %> //note that you can pass data to templates like this
<% } %>
<% if (data == 'bar') %>
<%- include('bar') %>
<% } %>
<% include('footer') %>
foo.ejs:
//some component here
If you want to read more, check the docs.
Hope this helps!
You can use Template Engine for that purpose because it enables you to use static template files in your application. At run time, the template engine replaces variables in a template file with actual values, and transforms the template into an HTML file sent to the client. This approach makes it easier to design an HTML page.
Some popular template engines that work with Express are Pug, Mustache, and EJS. The Express application generator uses Jade as its default, but it also supports several others.
Also check this link
I'm new in SailsJS so i have a question about rendering partial views.
I've came from .NET world and partial views in ASP.NET MVC are much more clever than in sails. In .NET MVC i can provide some controller as partial view path and this controller will be executed and partial view will be rendered with that controller data.
For example I want to show some account info in the corner of my website. So in .NET i can call partial view, providing controller path, this controller will query account info, provide it to partial view, and then this result will be inserted to main view.
In Sails i can call partial view, but all data (locals) for partial view will be pushed there from main view. So i have to put account information in every controller in application?
How can i solve this problem?
In other questions i've found that I can take username from req.session but it does not solve all cases. How can i show three random topics in page footer for example?
I think you are looking at the wrong place about the partial views.
This is a front-end problem .What I use for such partial views is Angular UI-router . Actually I am not sure if using angular is in the scope of the solution for you,So I'll keep this short . If you feel my method is useful ,you can comment it ,and I'll elaborate further on how to do it .
Depends on the template engine, that you use.
With ejs you can use <%- include('someview') %> or <%- include('someview', { mydata: { foo: bar} }) %>
The latter allows the include file to be called several times with diff data. E.g. <%- include('someview', { mydata: foo }) %> will copy foo (from locals) to the mydata key. This will be added to locals, so all other locals are available too.
As for providing the actual data, you can use a sails service. Just add data to res.locals.myKeyForTheInclude.
You will have to call the service each time.
But you can add it in config/http as a middleware.
middleware: {
myFoo: myService.myFunc,
order: [
...
'myFoo', // before router
'router',
...
],
All that is left is that each template needs the include.
You can not avoid that, only the template knows where the include should be.
But if you use a layout, that maybe it fits into the layout.
I am using ejs-locals to give me support for partials in express/node.js
The problem is the library has a bug when you include a partial within a partial. The 2nd partial include is trying to find the file relative to the grandparent or page.ejs that called the 1st partial.
So this requires I either flatten out my ./views so all files are only in ./views (no sub-dirs)...or I symlink to the partial from the directory that made the initial partial call.
Perhaps there is another/better way of doing this?
In a lot of my views, I have a face mash, that gives me html with people's avatars. I can't just use <% include faces %> and call it a day, because the collection of people comes from many different objects depending on the page from which it is called.
here's an example:
on an item page, I call <% include stats %>, which calls faces partial
<- partial('faces', { people: item.users }) %>
or on a list page, I call <% include stats %>, which calls faces partial
<- partial('faces' { people: list.users }) %>
The partial 'faces.ejs' just loops over people and spits out a link to their profile. But because I can't include a partial within a partial I'm stuck either sym-linking all over the place or trying something different.
./views/list/index.ejs calls a stats.ejs partial that calls faces.ejs partial...so I need to symlink ./views/list/faces.ejs to ./views/stats/faces.ejs for it to work.
You cannot pass data to a simple include, so I cannot pass in different collections of users depending on the context in which it was called.
<% include faces %> would require the face.ejs loop over either item.users or list.users hardcoded in faces.ejs
What else can I do that will work with nested partials/includes? I have filed a bug with ejs-locals, and a few others have as well, but its been a month w/o any fix.
How do have an admin user and how do I hide hyperlinks for non-admin users?
An alternative approach that I use regularly is to have another model called UserGroup. For example:
$ rails g scaffold user_group name:string description:text is_admin:boolean
You would then add a user_group_id:integer to your user model:
$ rails g migration add_user_group_id_to_users user_group_id:integer
In your user model, you could then add two instance methods to help you figure out if any specific user is a "normal" user or an "admin" user:
#app/models/user.rb
def normal?
self.user_group && !self.user_group.is_admin
end
def admin?
self.user_group && self.user_group.is_admin
end
This is probably over-kill for projects where there are only admins and non-admins, but is handy if you have many categories of users, such as ecommerce_manager, story_editor, etc.
I looked long and hard to find out how to do this, in the end it was too simple!
I didn't need route changes, loads of controller code or anything like that.
Just add a field in the database called admin_flag through a migration), then modify the Rails view form for new/edit to use it.
Then on the application/html.erb just add:
<% if current_user %>
<% if current_user.admin_flag == true %>
| <%=link_to(:categories, :categories) %>
| <%=link_to(:users, :users) %>
<% end %>
<% end %>
This will only show users and categories if the user logged in is admin too.
Do this after setting at least one admin user or you will need to use sql to set at least 1 admin user.
If I create tabs using one of the Grails GUI options (which one should I use), is it possible to turn tabs on and off, based on the current user? For example only users with a role of admin should see the Manage Users tab. And even anonymous users should see the Main Content tab.
Ideally, I'd like to use Spring Security ACL.
Just to add, sometimes you can add too much logic and coding in the view (GSP). You can push more of the code to the controller by using other options such as the navigation plugin along with the Spring-Security plugin. The nice thing is the view is just cleaner removing condition tags.
grails install-plugin navigation
Then in the controller just use the #Secured annotation. For example I created two tabs with two corresponding controllers.
#Secured(['ROLE_ADMIN'])
class SlidesController {
static navigation = [
group:'tabs', order:10, title:'Users', action:'index'
]
def index = {
.....
}
#Secured(['ROLE_ADMIN'])
class ProgramsController {
static navigation = [
group:'tabs', order:10, title:'Programs & Presentation', action:'index'
]
def index = {
.....
}
In the view:
<head>
... other head elems.
<nav:resources/>
</head>
<body>
<nav:render/>
... Your other stuff
</body>
Tabs automatically appears (would be also useful to make this view a layout GSP).
Yes, it's possible and pretty easy with the Acegi (Spring Security Plugin), see this section of the docs. You'll need to define some roles, and then describe how those roles apply to different URLS. Example (from link above):
/admin/=ROLE_USER
/book/test/=IS_AUTHENTICATED_FULLY
/book/**=ROLE_SUPERVISOR
There is also explanation about exactly how to do this in Grails In Action book.
Spring Security has a nice tag library for this. You can delimit rendering the tabs by using something similar to this:
<sec:authorize access="hasRole('supervisor')">
This content will only be visible to users who have
the "supervisor" authority in their list of <tt>GrantedAuthority</tt>s.
</sec:authorize>
You can just enable the jsp tag as normal:
<%# taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
Read more about it here if you like