display view regarding to authentication? - asp.net-mvc

When it comes to display a view regarding to authentication (view displayed depending to the visitor if he's a user or not). I face many choices. So I need your help to show me how i deal with such situation :
Using 2 views (one for the users and other for visitors), or just one view.
using 2 actions (one with authorize filter and the other without), or just one action.
And why the choices you suggest is better ?

You don't have to not use Authorize attribute. It's main function is to setup the User in the context, and then by default, it also checks that they are logged in. However, this last part can be overridden by using the AllowAnonymous attribute as well:
[Authorize]
[AllowAnonymous]
public ActionResult SomeView()
{
...
}
So, now your view will have a User to play with, and you can dynamically present different pieces of the view using that based on auth status:
#if (User.IsAuthenticated)
{
<p>Logged in</p>
}
else
{
<p>Anonymous</p>
}
EDIT (for clarification)
The Authorize attribute actually does two distinct things for you. First, it setups all the machinery for recognizing a user: reads the cookie or whatever, checks the authentication status, pulls in the user's info, if they are authenticated, etc. Second, it validates that the user is in fact logged in. Using AllowAnonymous skips this second part and allows anyone, logged in or not, to access the view, BUT and this is key, you still need the first part to know stuff like whether you have an authenticated user or not.
So, simply, using both the Authorize and AllowAnonymous attributes together means essentially, "see if the user is logged in, but don't require it to access this view". That allows anonymous users to still reach the page, but enables you to still deliver unique or different content to an actual logged in user.

Related

MVC passing values through several views

I have a login view for a user to authenticate: after he inserts his username and password, the next view has a section with welcome, username message. I pass this information through a ViewBag.welcomeMsg and everything is smooth.
When I advance to another view, that section no longer contains the message as the ViewBag.welcomeMsg is defined in the first login controller and gets erased after that.
I don't want write in every controller ViewBag.welcomeMsg = "...";
My question: is there a way to pass a variable like ViewBag that persists and can be accessed from every view of the web application? Like a static field?
If you just want to show the welcome message on your view when user is authenticated then just modify your view like this :
#if (Request.IsAuthenticated)
{
<text>Welcome, #User.Identity.Name</text>
}
Can check with the TempData which will be available till start of the next view rendering. so that you can set it to the other viewbag from tempData.
It very much depends on how you handle the authentication process. If you are using FormsAuthentication for example, then the user information will be stored in User.Identity.Name. You can access User property from various contexts like controller, view, etc.
On the other hand if you are handling the authentication by yourself, my suggestion to you would be to do any of the following (I am writing this from top of my mind, so if I miss a name of a property, forgive me):
Store username in a cookie, and in Global.asax handle PostAuthenticated event where you will read the username (if authenticated) from the cookie. After that create a GenericPrincipal object with GenericIdentiy and assign it to a Controller.User
Store the information in a session (the easiest of all) and pass it around. However, the problem with this is if you have a sessionless controller in which case you cannot rely on this approach.
I wrote an article a long time ago about working with roles and principals, but you can get a picture on how to handle your problem with this solution http://mvcdeveloper.wordpress.com/2013/06/08/passing-user-roles-to-httpcontext-user/

Prevent access to page based on Authentication

I have an ASP.Net MVC 4 Website. When I started this site I had little to no web programming experience, and I don't believe I set up all of it appropriately.
I have pages, such as Home, Login, Register, which I consider public,
pages like, VerifyPIN and AccountCreated, which I consider internal
and pages like Dashboard and Profile, which are private.
I feel public pages should be accessed by anonymous users, but Login and Register should not be accessible once a user logs in.
Internal pages I want to only be available upon server redirect and never through the browser, aka I don't want a user to be able to type in www.MySite.com/AccountCreated.
And private pages are for a logged in user only.
I feel I have private pages working fine, but I don't know how to limit access to the other pages as described above. Perhaps my notion to not allow a logged in user to access the log in page is miss-found.
My site is relatively small due to the ajax nature of the site. I use [AllowAnonymous] on all public pages but then a logged in user can still access those and I am not sure how to prevent that.
My questions are,
How can I prevent a user from accessing a page via the address bar (www.MySite.com/AccountCreated)
How can I prevent access to a [AllowAnonymous] page once a user has logged in.
EDIT
Is it normal to prevent logged on users from accessing certain anonymous pages, such as login?
You may always check if user is already logged in. If he did, he will be redirected to another page:
public ActionResult AccountCreated(some params)
{
if (Request.IsAuthenticated)
{
return RedirectToAction("Index")
}
else
{
// login logic here
}
}
You may also check it directly in View:
#if (Request.IsAuthenticated)
{
<span> You are already logged in</span>
}
else
{
//Login form here
}
well for your first question you can use the [Authorize] action filter.
For your other question, I guess you will have to write your own implementation. You will need to create a new IAuthorizationFilter and use it instead of [AllowAnonymous]
Just some ideas(didn't try them actually).
For question 1 - if AccountCreated is an action that means that the registration form actually POSTs to that URL - i.e. It is accessible from outside. I suggest you apply an HttpPost attribute to it so it will process only POST requests - there is not much you can do here
For point two you can do something like this in your action method
if (HttpContext.User.Identity.IsAuthenticated)
{
return RedirectToAction("Index", "Home");
}
else return View();
Just a thought, Signout user when a user goes to Login or Register page .
Hope you have not provided any link on private pages for a user to go to login or Register
page or check if user is authenticated redirect it to Home page, frankly you can not stop a user to write a URL and pressing the enter button, or just give a notification that You'll be logged out if you proceed to whatever page.

ASP.Net MVC: Check if URL is Authorized

I'd like to simply check from a Controller whether another URL is authorized.
So for example, I'd like to call into a Controller like so:
[HttpPost]
public ActionResult IsUrlAuthorized(string url)
{
bool isAuthorized = // What do I put here?
return Json(isAuthorized);
}
So I'd like to know what I could call to check on whether the current user is authorized for the passed-in URL or not. I'm guessing the answer has something to do with Routes, which sit a little bit outside MVC?
This is a somewhat similar question but not quite the same thing:
ASP.NET MVC. Check if user is authorized from JavaScript
Since the user may or may not be authorized in general, but may not have the right permissions or role assignments to see a specific URL.
Ideas?
Update: I use standard MVC authorization attributes to lock down my app, so I'll just give an example of what that looks like here. In MVC Routes map to Controllers. A single method on a Controller can be restricted to one or more Roles:
public class HomeController : Controller
{
[Authorize(Roles = "User, Moderator")]
public ActionResult ListRecentPosts()
{
. . .
}
}
Or, an entire Controller can be restricted to one or more roles:
[Authorize(Roles = "Admin")]
public class AdminController : Controller
. . .
The actual URL that any of these controller methods responds to is based on a default mapping in a standard MVC app:
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
But, you can be nice to your users and make URLs guessable by adding a lot more Routes - as a result, a Controller method can have many names that point to it. You can't just assume and infer the controller name from the URL (even if it maps out that way for half the URLs in the site).
So presumably I either need a way to ask the Routing engine directly whether a URL is authorized for the current user, or a 2-step of asking the Routing engine for which Controller and Method, then ask if those are authorized - hopefully not by using Reflection and matching Roles directly as that again would appear to assume too much.
Update 2: The way this came up is I have an Account strip at the top of my app. Its state can change by selecting one of several accounts you're authorized as. Depending on where you are in the app, the account you chose might have authorization to view this page - and you might be in the middle of filling out a form you don't want to lose. So the naive approach - just refresh when they pick another account - is harmful, and a waste of the user's time even if there is no form and they're just reading a page that's all text.
While that convenience to the user is nice, the user is going to fairly assume that pages they can't see as a user who shouldn't have permission really are denied (and, it would be harmful to leave them on a page that's forbidden - actions taken from it will fail). So I need to know whether to redirect away based on their new permissions.
One of the things I love about .Net is the way many of its best libraries decompose so well, so you can easily recompose things that are part of its normal functionality, or a new twist. Both the Routing module and MVC appear to be very well constructed, so I have to suspect this can be done.
The cheap hack is to ensure that my authorization module returns a consistent redirect status code when a user isn't authorized, and when the user changes their account in the account strip, fire 2 AJAX calls: One to change account, and then a second to the current page over AJAX just to check the HTTP Status Code. 200 OK means leave the page as is, Redirect means follow the redirect. Obviously this is a little ugly, involves an extra HTTP call, creates a false hit in the logs, and makes an assumption about how authorization is handled across the app.
There could be a secondary concern - the page might be authorized, but just change how it works or looks. This particular app has no change in look based on account (besides the account strip itself), and I can handle functionality changes by just providing a custom event that forms listen to - they can reload any relevant data from the server in response to it.
Using UrlAuthorization.CheckUrlAccessForPrincipal only works if you're only using URL authorization. But for MVC using Routing, we highly recommend that you don't use URL authorization to secure an app.
Instead, we recommend using Authorization attributes on the controller class. The reason is there could be multiple URLs that call the same controller action. It's always better to secure the resource at the the resource and not just at the entry ways.
In this particular case, you'd have to get an instance of the controller given the URL. THat's a little tricky as you'll basically have to run the MVC pipeline from the point where you have the URL to the point where you have the controller. It's possible, but seems heavyweight.
I wonder if there isn't a better and simpler way to accomplish your goals. What is it you're really trying to do?
UPDATE: Based on your scenario, it sounds like this is an initial check just for UI purposes. Perhaps all you need to do is make an asynchronous Ajax request to the URL and check the HTTP Status code. If it's a 401 status code, you know the user is not authorized. That seems like the safest bet.
How about UrlAuthorizationModule.CheckUrlAccessForPrincipal method.
UrlAuthorizationModule.CheckUrlAccessForPrincipal Method (System.Web.Security)

ASP.NET MVC custom membership for beginners

I am creating my own website and blog and I want for first time just me in database (my name and password) and maybe later some registration for others but first log in just for me and administration with authorization. I don´t want to use Membership from MS. I want try to create my own from start so I am looking for guide for beginners but I found big guides with roles, rights. I want just small example with check username, password in database with log on data.
Thanks for help
Libor
Even if you don't want to use the membership and role provider data store you can still utilize the authentication. Trust me, it's a lot easier than building your own. Here's how it works:
We'll say you already have your user storage setup for retrieving the username and their password. For the sake of simplicity I'm going to pretend you have a static class called DataLayer that contains your data retrieval methods for pulling info from the database (or whatever storage you use).
First you need a way to let the user log in. So set up a page with username and password fields. Then in the action method that the page posts to set up a quick if statement:
if (DataLayer.UserExists(userModel.Username))
{
User userFromDB = DataLayer.GetUser(userModel.Username);
if (userFromDB.Password == userModel.Password)
{
FormsAuthentication.SetAuthCookie(userFromDB.Username, checkBoxRememberMe.Checked);
//Use userFromDB as the username to authenticate because it will
//preserve capitalization of their username the way they entered it
//into the database; that way, if they registered as "Bob" but they
//type in "bob" in the login field, they will still be authenticated
//as "Bob" so their comments on your blogs will show their name
//the way they intended it to.
return "Successfully logged in!";
}
}
return "Invalid username or password.";
Now that they are authenticated you can just use Page.User.Identity.IsAuthenticated in your code to find out if they are logged in. LIke this:
if (User.Identity.IsAuthenticated)
{
DataLayer.PostBlogComment(User.Identity.Name, commentBody);
//Then in your controller that renders blog comments you would obviously
//have some logic to get the user from storage by the username, then pull
//their avatar and any other useful information to display along side the
//blog comment. This is just an example.
}
In addition, you can lock out entire action methods or even whole controllers to users that are authenticated through the forms authentication provider. All you have to do is add tags like these to your action methods/controllers:
[Authorize]
public ActionResult SomeActionMethod()
{
return View();
}
The [Authorize] attribute will prevent users that are not logged in from accessing that action method and it will redirect them to your login page. You can use this same attribute to filter out roles if you are using the built in roles provider.
[Authorize(Roles="Admin, SalesReps")]
public ActionResult SomeActionMethod()
{
return View();
}
These attributes can also be added above the controller class to apply it's logic to the entire controller.
EDIT: To log a user out all you need to do is call FormsAuthentication.SignOut();
Hey #Bibo, good for not choosing the Membership providers. I think a UserService or similar which provides methods for creating, authenticating users and some few more methods should be enough. As a suggestion, use password hashing and a password salt for the user´s password. Here is a good link to look at. Also have a look at this answer I gave some time ago.
Good luck!
EDIT: The rememberMe parameter should be named keepMeSignedIn instead.
This article on forms authentication gives you loads of info for creating your own simple security system, especially the bit about FormsAuthenticationTicket.
http://support.microsoft.com/kb/301240

manage 2 different Log In sections

I'm creating a site with 2 different sections (main site and admin) and both of them need authentication.
I have the main section already created and it works fine using FormsAuthentication.
now, how do I go about creating the admin section? Can I use FormsAuthentication again?
thanks
user - yes you can.
what you need to do is to create roles (such as webuser and admin) and assign the user to the appropriate role as required (you can do this either when setting the user up initially or later as an edit on their profile). anyway, getting back to the question. inside your controller, you'd then investigate the roles that existed for that logged in user and this would determine which controller actions they had access to as well as determining which view to present, should the action be 'shared' between roles.
within the controller, you can decorate the action with the following code:
[Authorize(Roles="admin")]
public ActionResult IndexAdminOnly() // you'd never have an action named this - purely to make the point
{
// your logic here
}
conversely, you could do it inside the controller:
[Authorize]
public ActionResult Index()
{
if(Roles.IsUserInRole("admin")){
// your admin logic here
}
if(Roles.IsUserInRole("webuser")){
// your webuser logic here
}
}
this is it at it's very simplest. hopefully you can google a few more links to get you over any issues that arise once you get going, or drop a note here.

Resources