Retrieve Session variables into ASP.NET MVC 4 (razor, view) - asp.net-mvc

I wrote many websites with PHP. Now, I have to create website with ASP MVC 4 (c#) and I am stuck with Sessions.
I.E. the user should go to login page, enter his/her login and password. If they are correct, in controller, I set the session with UserId, like this:
Session["UserId"] = 10
This UserId value is used for showing PartialViews (login form or (after login) some application menus). How can I get this UserId inside Razor view ?
After this in View:
if (Session.UserId == 10) { #Html.Partial("LoggedMenu") }
i've got exception with StackOverflow. :/

you're doing it wrong...
Session[<item name>] returns a string, you should compare with a string as well, or cast it, so, either (int)Session["UserId"] == 10 or Session["UserId"] = "10".
you also are invoking a property that does not exist Session.UserId will not exist as Session is like an NameValueCollection, you call it by request it's item name.
at the end, you should write
#if (Session["UserId"] == "10") {
Html.Partial("LoggedMenu");
}
You say your are learning, so I would like to point out 2 quick things:
You should take advantage of the ASP.NET MVC Course that is available for free in the home page http://asp.net/mvc (right side when you read "Essential Videos")
Create an MVC3 project and see how they do it as it comes ready out of the box with Membership

#if (Session["UserId"] != null && Session["UserId"] == 10 ) {
Html.Partial("LoggedMenu");
}
Apart from that: for identity management better use the out of the box membership system

Below is a an example:
Controller:
if (Session["pageInitCounter"] == null)
{
Session["pageInitCounter"] = 1;
}
else
{
int counter = Convert.ToInt32(Session["pageInitCounter"]);
counter++;
Session["pageInitCounter"] = counter;
}
View:
#Html.Hidden("pageInitCounter", Session["pageInitCounter"])
Javascript:
alert($("#pageInitCounter").val());

Related

MVC linq query handle situation where sequence contains no elements

I have a simple login form on my mvc application and it works correctly except for when you try to login with a user that isn't in the database.
It will throw an error Sequence contains no elements which makes sense since theres no matching users in the database although I try to handle it in the code it is not doing it.
// POST: Login User
[HttpPost]
public ActionResult Login(UserAccount user)
{
using (MyDbContext db = new MyDbContext())
{
var usr = db.Users.Single(u => u.UserName == user.UserName && u.UserPassword == UserPassword);
if (usr != null)
{
Session["UserID"] = usr.UserId.ToString();
Session["Username"] = usr.UserName.ToString();
return RedirectToAction("LoggedIn");
}
else
{
ModelState.AddModelError("", "Username or Password Incorrect");
}
}
return View();
}
Single will throw an exception if no match is found, or too many are found. Using SingleOrDefault like so returns null in the case where no match is found:
var usr = db.Users.SingleOrDefault(...)
This sets you up for the null check you're doing right afterwards.
So...As some people said in the comments above, you could just simply use the following query and then do your null check:
var usr = db.Users.SingleOrDefault(u => u.UserName == user.UserName && u.UserPassword == UserPassword);
That being said, I would recommend looking into using the built in ASP Identity framework for authentication and authorization - unless you need a custom implementation for your application, you can avoid a lot of testing (and potential bugs) as well as get a ton of cool out-of-the-box features. I would recommend checking out the resources here for more information.

How do i write code in ASP.NET MVC to check whether user accepeted terms and condition

In my ASP.NET MVC project I need to write code to check for users whether they accept terms and condition. I am using Entity framework and Database first approach. I have Table called Appterms, in which I have field called TermsAccepted and Date. I also have other fields in Appterms table such as GatewayUserId and termId. ' GatewayUserID has ID of registered users and termId is primary key. 'Termsaccepted' field is of bit type.
I tried to follow custom attribute function which is posted in this post
MVC 3 How can I make a user view a warning/disclaimer screen but not able to implement as per my needs.
I am using this post Getting current user id to get id of current user. So after this how can i return 0 or 1 to check they accepted terms and condition.
This is the code snippet I am trying to use :
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
Inherited = true, AllowMultiple = false)]
public class AcceptedTermsCheck : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Check if AcceptedTC is set to true
// If set, then do nothing
// Otherwise redirect to TC page
}
}
Here to check if user accepted terms, i should return true, that is '1' in my GatewayUserId field, if not it should return false.But I don't know how to do this. And also I got to know I should create session to achieve this task. But never worked on it before.
Any help??
Thanks..
I think this is what you want to do. you can post back data or use jquery to post to a action to check and if the terms are accepted and then enable the submit button for a better user experience. Whichever way you choose, you can do something like this.
var dataEntityModel = new YoursEntities();
AppTerm currentTerm = dataEntityModel.Appterms.ToList().
where(x=>x.GatewayUserId == yourCurrentUserID
&& x.termid == yourTermId).FirstOrDefault();
if(currentTerm.TermsAccepted == true)
{
}
else
{
RedirectToAction("action","controller");
}
userlogin login = db.userlogins.Where(j => j.email == name && j.password == password && j.status == 1)
.FirstOrDefault();

Using OpenID/OpenAuth in MVC3 app with overridden authentication method

We override the basic authentication in an MVC3 application by calling a webservice with the user's credentials and returning a WCF structure that contains the user's ID, a "LogonTicket". This LogonTicket is used to "authenticate the user for each call made to the webservice.
Now, we override by replacing the defaultProvider in the Web.config. All we do in this overridden provider is
to override the ValidateUser() function. That is where we call the web service with their credentials and return
the "LogonTicket".
This is the LogOn() function from our AccountController, essentially the base code from the template:
public ActionResult LogOn(LogOnModel model)
{
string ReturnUrl = "";
if (HttpContext.Request.UrlReferrer.Query.Length > 11)
{
ReturnUrl = Uri.UnescapeDataString(HttpContext.Request.UrlReferrer.Query.Substring(11));
}
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
&& !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
{
return Redirect(ReturnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
ViewBag.MainWebsite = MainWebsite;
return View(model);
}
This is the overridden ValidateUser() function from our new default provider:
public override bool ValidateUser(string username, string password)
{
MyServiceClient mps = new MyServiceClient();
string sha1password = HashCode(password);
LogonInfo logonInfo = mps.GetLogonTicket(username, sha1password);
if (logonInfo.LogonTicket != "" && logonInfo.LogonTicket != "0")
{
// Authenticated so set session variables
HttpContext.Current.Session["LogonTicket"] = logonInfo.LogonTicket;
HttpContext.Current.Session["ParticipantID"] = logonInfo.ParticipantID;
return true;
}
else
{
return false;
}
}
I'm not really sure how to combine the use of the two, so my questions are:
How can I implement OpenID and Facebook logins and keep my current authentication method?
How can we "map" the OpenID user with our current user DB values? We MUST know so we can retrieve their info.
I know we can retrieve their email address but what if their OpenID email is different than the one they use for their record on our site?
Are there any examples of how to do this, anywhere?
Thanks for looking at my question.
I have done a project which required multiple log-on possibilities (custom account, Google and Facebook)
In the end your authentication with ASP.NET is entirely dependant on your configuration. (In your case it is FormsAuthentication) this means that FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); basicly determines everything in regard to your user and where you set this isn't restricted.
You have now basicly the same implementation as we started out with, using a MembershipProvider to handle your own custom account. You only need to expand now to facilitate the openIds. You would have to expand your Controller with various actions for each login type (Now you have ActionResult LogOn() you can add to that for example: ActionResult LogOnOpenId()). Inside that method you basicly call the same code but instead of Membership.ValidateUser(model.UserName, model.Password) you call the OpenId services.
I have provided below an example of our google implementation using dotnetopenauth. The service method uses formsService.SignIn(userId.Value.ToString(), false); which basicly calls FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); (we only do some custom behaviour there in regard to the SecurityPrincipal but this doesn't affect your Authentication process). You can also see that we make a new account when we receive a new user. To solve your question part 2 we have implemented a profile which can be merged if you can provide another login. This allows our users to keep their account consolidated and use whatever login method they like.
For examples in regard to multiple signons I will refer to the answer of Tomas whom referenced StackExchange as a good example. Also I'd advise you to install MVC4 and VS2012 and just do a File > New Project. The newest default template of MVC includes openid implementation alongside a custom login!
Example google openid implementation:
The controller method:
public virtual ActionResult LoginGoogle(string returnUrl, string runAction)
{
using (var openId = new OpenIdRelyingParty())
{
IAuthenticationResponse response = openId.GetResponse();
// If we have no response, start
if (response == null)
{
// Create a request and redirect the user
IAuthenticationRequest req = openId.CreateRequest(WellKnownProviders.Google);
var fetch = new FetchRequest();
fetch.Attributes.AddRequired(WellKnownAttributes.Name.First);
fetch.Attributes.AddRequired(WellKnownAttributes.Name.Last);
fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
fetch.Attributes.AddRequired(WellKnownAttributes.Preferences.Language);
req.AddExtension(fetch);
req.RedirectToProvider();
return null;
}
_service.ConnectViaGoogle(response, TempData);
}
The service method:
public void ConnectViaGoogle(IAuthenticationResponse response, TempDataDictionary tempData)
{
// We got a response - check it's valid and that it's me
if (response.Status == AuthenticationStatus.Authenticated)
{
var claim = response.GetExtension<FetchResponse>();
Identifier googleUserId = response.ClaimedIdentifier;
string email = string.Empty;
string firstName = string.Empty;
string lastName = string.Empty;
string language = string.Empty;
if (claim != null)
{
email = claim.GetAttributeValue(WellKnownAttributes.Contact.Email);
firstName = claim.GetAttributeValue(WellKnownAttributes.Name.First);
lastName = claim.GetAttributeValue(WellKnownAttributes.Name.Last);
language = claim.GetAttributeValue(WellKnownAttributes.Preferences.Language);
}
//Search User with google UserId
int? userId = _userBL.GetUserIdByGoogleSingleSignOnId(googleUserId);
//if not exists -> Create
if (!userId.HasValue)
{
_userBL.CreateGoogleUser(
googleUserId,
firstName,
lastName,
email,
language,
DBConstants.UserStatus.DefaultStatusId,
out userId);
}
if (userId.HasValue)
{
_userBL.UpdateLastLogon(userId.Value);
var formsService = new FormsAuthenticationService();
formsService.SignIn(userId.Value.ToString(), false);
AfterLoginActions(tempData);
}
}
}
Any questions or comments? I'll gladly hear them.
it should be perfectly possible to have multiple authentications methods. All IIS / ASP.net cares about is the FormsAuthentication cookies. So you would have one set of actions for your standard username/password auth, and another for OpenId. This is at least what I have done on one project.
You can't even trust the openId provider to give you an email address! A common solution to this problem is to allow a user to attach multiple OpenId identifiers (URI's) to the his account after logging in. This is e.g. how StackOverflow works. If this is the first time the user visits the system then you can auto create a new account, or force the user through a signup process.
When I added the OpenId support in the system mentioned, it had an existing table used to store username and password(users table). I added a new table with a many to one relationship with the users table, and used this to store the URI's.
As mentioned above StackOverflow it self is a good place to start, also there are a lot of good examples in the http://www.dotnetopenauth.net/ project.
As far as I know the source of SO is not public, and they are using the dotnetopenauth project.
This may be to abstract, but this library is a openId (among other things) for the open source orchard CMS: http://orchardopenauth.codeplex.com/
I hope this helps, but if you have any questions then please expand your question with more details.

Custom Authorize attribute HttpContext.Request.RawUrl unexpected results

We're building an application that is a Silverlight client application, but we've created an MVC controller and a few simple views to handle authentication and hosting of the Silverlight control for this application. As part of the security implementation, I've created a custom Authorization filter attribute to handle this, but am getting some unexpected results trying to properly handle redirection after authentication.
For example, our Silverlight application's navigation framework allows users to deep-link to individual pages within the application itself, such as http://myapplicaton.com/#/Product/171. What I want, is to be able to force a user to login to view this page, but then successfully redirect them back to it after successful authentication. My problem is with getting the full, requested URL to redirect the user to from within my custom authorization filter attribute class.
This is what my attribute code looks like:
public class RequiresAuthenticationAttribute : FilterAttribute, IAuthorizationFilter
{
protected bool AuthorizeCore(HttpContextBase httpContext)
{
var cookie = Cookie.Get(SilverlightApplication.Name);
if (SilverlightApplication.RequiresLogin)
{
return
((cookie == null) ||
(cookie["Username"] != httpContext.User.Identity.Name) ||
(cookie["ApplicationName"] != SilverlightApplication.Name) ||
(Convert.ToDateTime(cookie["Timeout"]) >= DateTime.Now));
}
else
return false;
}
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext != null && AuthorizeCore(filterContext.HttpContext))
{
var redirectPath = "~/login{0}";
var returnUrl = filterContext.HttpContext.Request.RawUrl;
if (string.IsNullOrEmpty(returnUrl) || returnUrl == "/")
redirectPath = string.Format(redirectPath, string.Empty);
else
redirectPath = string.Format(redirectPath, string.Format("?returnUrl={0}", returnUrl));
filterContext.Result = new RedirectResult(redirectPath);
}
}
}
So in this case, if I browse directly to http://myapplicaton.com/#/Product/171, in the OnAuthorize method, where I'm grabbing the filterContext.HttpContext.Request.RawUrl property, I would expect it's value to be "/#/Product/171", but it's not. It's always just "/". Does that property not include page level links? Am I missing something?
The # sign in URLs (also called the fragment part of an URL) is only used by browsers to navigate between history and links. Everything following this sign is never sent to the server and there's no way to get it in a server side script.

ASP.NET MVC check if user belongs to [x] group

Maybe I'm approaching this the wrong way and should be doing everything in action filters, in which case please point me in the right direction!
I'm setting up my ASP.NET MVC application so that the one HomeController Index action delivers two different types of content, like so:
if(Request.IsAuthenticated)
return View("IndexRegistered");
else
return View("IndexGuest");
This is fine but say I want to split it into three so Administrator members get their own page...
if(Request.IsAuthenticated)
{
if( /* user is a member of administrators */)
return View("IndexAdministrator");
else
return View("IndexCustomer");
}
else
return View("IndexGuest");
Can someone enlighten me as to the missing piece of this puzzle?
Use the Roles property of the Authorize Action Filter:
[Authorize(Roles="Administrators,Moderators")]
public ActionResult SomeAction(){
}
Or use the User.IsInRole() method:
if(User.IsInRole("Administrator")) { ... }
If you look at the Authentication provider which comes out-of-the-box in the default MVC project templates it's easy to add your own role support there and track it in session, so your code above would become:
if(Request.IsAuthenticated)
{
if(Session["Role"] == "Administrator")
return View("IndexAdministrator");
else
return View("IndexCustomer");
}
else
return View("IndexGuest");
and then opens possibilities like:
if(Request.IsAuthenticated)
return View("Index" + Session["Role"]);
else
return View("IndexGuest");

Resources