I just learn about ASP.NET MVC. I hava a website with this following scenario:
Login -> Main Page (Index) -> Edit Page (Edit)
So, In LoginController when user login, it will redirect to main page and edit a record from MainPage.
Everytime a new record is created through ASP.NET MVC, the system will send an email to manager. Within email message, there is a hyperlink that will redirect the manager to edit form. But first, he needs to login because the edit form cant be opened unless he login.
Ex:
http://localhost:1212/Main/Edit/ID-001
I have add Authorize Attribute within MainController. But It's only work for Main Page. So I can open Edit Page even I am not login yet.
Here is the MainController:
[Authorize]
public class MainController : Controller
{
string connString = #"Data Source=DESKTOP-FSET3FF,1433; Initial Catalog=INOVA_Data; User Id=sa; Password=Copoe113";
public ActionResult Index(string username)
{
if (Session["username"] != null)
{
string user = Session["username"].ToString();
SqlConnection conn = new SqlConnection(connString);
conn.Open();
string sqlQuery = #"select Animals, Gender from dbo.Animals where Pemilik = #user";
//string h = x => x.
SqlCommand cmd = new SqlCommand(sqlQuery, conn);
cmd.Parameters.AddWithValue("#user", user);
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
conn.Close();
return View(dt);
}
else
{
return RedirectToAction("Login", "Login");
}
}
public ActionResult Edit()
{
return View();
}
}
The Second Question, Above I have write my website scenario, that is
Login-> MainPage (Index) -> EditPage (Edit)
Based On Hyperlink On Email, How to make application Redirect to EditPage without redirect to MainPage.
Login -> EditPage (Edit)
EDITED 2nd question
In short, when user's trying to access edit view directly, the application will redirect user to login view. And when heelr login success , the application will redirect user to Edit View.
But now, when login success, the system will redirect the user to main view. How to make the application redirect to edit view after login ?
Important note : (Based on #Tashi Comment, I added this note) If you are use mvc basic application with admin panel than do not worry about the authentication and authorization for whole application with session management.
This is we need when we explicitly use our customization of app and that has to be implement in every controller. Rather than use direct controller for inheritance i.e. MainController : Controller , use custom controller where you check authentication.
/*You have to inherit this basecontroller in every controller*/
public class MainController : BaseController
{
your actionmethods
}
And BaseController like
public class BaseController : Controller
{
public BaseController()
{
if (string.IsNullOrEmpty(SessionManager.SiteUrl))
{
SessionManager.SiteUrl = ConfigurationManager.AppSettings["SiteUrl"].ToString();
}
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
if (SessionManager.UserId == -1)
{
switch (filterContext.ActionDescriptor.ActionName.ToLower().Trim())
{
case "addeditcontact":
ViewBag.hdnPopupLogout = "0";
return;
default:
filterContext.Result = new RedirectResult(Url.Action("Login", "Home"));
break;
}
}
}
}
Add another property class for session management
public class SessionManager
{
public static int UserId
{
get
{
if (HttpContext.Current.Session["UserId"] != null)
{
return Convert.ToInt32(HttpContext.Current.Session["UserId"]);
}
else return -1;
}
set
{
HttpContext.Current.Session["UserId"] = value;
}
}
public static string UserName
{
get
{
if (HttpContext.Current.Session["UserName"] != null)
{
return Convert.ToString(HttpContext.Current.Session["UserName"]);
}
else return string.Empty;
}
set
{
HttpContext.Current.Session["UserName"] = value;
}
}
//reset user detail and add your custom property
public static void SignOutUser()
{
UserId = -1;
UserName = string.Empty;
}
}
While login set userid in session variable in HomeController like
public ActionResult Login()
{
if (SessionManager.UserId == -1)
{
HttpCookie cookie = Request.Cookies["Login"];// Request.Cookies["Login"];
if (cookie != null)
{
ViewBag.hdnUserID = cookie.Values[0];
ViewBag.hdnPassword = cookie.Values[1];
ViewBag.hdnRemember = "true";
}
return View("Login");
}
else
{
return RedirectToAction("Index", "Home");
}
}
Now this is your architecture ready, I will give your answer
This above things prevent unauthorized access, if there is no user
without authentication.
Now second question is redirect to edit page when hyperlink click. for this while define hyperlink, either create actionmethod to redirect or you can use javascript / ajax method (For authenication) to redirect page.
You need to design html at your end for grid. As this below image.
and above last td of cell in html render as this
<td width="25%" >
<a title="Edit" style="cursor:pointer" onclick="popupContacts(-2147481891,false );">Edit</a>
<a style="cursor:pointer" title="Associate With Client" onclick="popupAssociateClient(-2147481891 );">Associate With Client</a>
<a style="cursor:pointer" title="Update Contacts" onclick="popupUpdateContacts(-2147481891 );">Update Contacts</a> <a style="cursor:pointer" title="Export VCF" onclick="ExportContacttoVcf(-2147481891 );">Export VCF</a>
</td>
for js, redirect to another page, where we first check that user have proper rights else redirect to login in actionmethod.
function popupContactsDetails(clientid, contype) {
window.location.href = URL + "Home/ShowEditContact?Id=" + clientid + ",contype=" + contype;
}
OR You can use the same function as(may be some thing wrong in code as I maniputlate code to publish here, but understand the concept behind this)
function popupContactsDetails(clientid, contype) {
$.ajax({
url: URL + "Home/ShowEditContact?Id=" + clientid + ",contype=" + contype,
type: 'get',
dataType: 'json',
async: false,
// data: ko.toJSON(this),
contentType: 'application/json',
success: function (result) {
if (result = null) {
alert("you are access wrong page);
window.location.href = URL + "Home/login;
} else{
window.location.href = URL + "Home/yourpageurl;
}
}
});
}
Related
I want to redirect to welcome page and it should show/hide html elements according to user type. I have written return View("Welcome", adminvar); but it returns the Welcome page inside login URL.
Upon refresh it shows popup warning of form resubmission. I want to redirect to Welcome page. I tried this
return RedirectToAction("Welcome" , adminvar);
but it's not working.
[HttpPost]
public ActionResult Login(tbl_Admin adminObj)
{
studentDBEntities db = new studentDBEntities();
var adminvar = db.tbl_Admin.Where(x => x.Email == adminObj.Email && x.Password == adminObj.Password).Select(s=> new tbl_AdminVM {
AdminId = s.AdminId,
Email = s.Email,
Name = s.Name,
Password = s.Password,
Type = s.Type
}).FirstOrDefault();
if (adminvar != null)
{
/* return RedirectToAction("Welcome" , adminvar);*/
return View("Welcome", adminvar);
}
else
{
return View();
}
}
public ActionResult Welcome()
{
ViewBag.Message = "Welcome Admin - Admin Account Page";
return View();
}
View:
#if (Model.Type)
{
<center><p>#Html.ActionLink("Admin Management", "ListAdmin")</p></center>
}
Here you are returning Welcome View to the login method that will render welcome view content on login page and will not be redirected to welcome page.
What you can do is, after successful login, redirect to Welcome Action.
return RedirectToAction("Welcome", new { userType = adminvar.Type });
And modify Welcome action as below
public ActionResult Welcome(string userType)
Inside Welcome action get the value of usertype and send it to Welcome view using Viewbag.
ViewBag.userType = userType;
Use the value of ViewBag.userType on Welcome Page to show/hide html elements.
You Can redirect to action
return RedirectToAction(“ActionName”,”ControllerName”);
or
return RedirectToAction(“~/ControllerName/ActionName”);
My Home Controller Like this:
public class HomeController : Controller
{
....
[ActionName("Login")]
public ActionResult Login()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(string UserName, string Password)
{
try
{
var query = user_Repository.Login(UserName, Password);
if (query != null)
{
Session["UserName"] = query.UserName;
Session["IsAdmin"] = query.IsAdmin;
return RedirectToAction("Index", "News");
}
ViewBag.ErrorMessage = "نام كاربري يا رمز عبور صحيح نمي باشد";
return View();
}
catch (Exception e)
{
ViewBag.ErrorMessage = " خطا!!! ";
return View();
}
}
public ActionResult LogOut()
{
if (Request.Cookies["user"] != null)
{
var user = new HttpCookie("user")
{
Expires = DateTime.Now.AddDays(-1),
Value = null
};
Response.SetCookie(user);
Response.Cookies.Clear();
}
if(Session["UserName"] != null)
{
Session["UserName"] = null;
Session["IsAdmin"] = null;
}
Session.Clear();
return RedirectToActionPermanent("Index");
}
}
When i Use ActionLink in _Layout to Run Logout Action in Home Controller , this ActionLink Instead of executing Logout Action, Login will be executed!!!
My ActionLink Like this:
#Html.ActionLink("Log Off", "LogOut", "Home")
where is my wrong??? why #Html.ActionLink("Log Off", "LogOut", "Home") run Login Action????????????????????
i use this code for run that LogOut Action in my _Layout and this code work Correct...
#using (Html.BeginForm("LogOut", "Home", FormMethod.Post, new { role = "form" }))
{
#Html.AntiForgeryToken()
<input type="submit" value="خروج" class="btn btn-primary" />
}
This is a text that stackOverflow lets me send the text because stackOverflow says i should give more explanations and say "it looks like your post is mostly code; please add some more details"!!! i dont have any more detail.... i explain all of that ;)
Do not put your Logout action in a Form. Your ActionLink should work correctly if you have given the correct parameters to it.
Your ActionLink would look like this:
<a href='#Url.Action("LogOut", "Home")'>Log Out</a>
And your Controller action result would look like this:
public ActionResult Logout()
{
if (Request.Cookies["user"] != null)
{
var user = new HttpCookie("user")
{
Expires = DateTime.Now.AddDays(-1),
Value = null
};
Response.SetCookie(user);
Response.Cookies.Clear();
}
if(Session["UserName"] != null)
{
Session["UserName"] = null;
Session["IsAdmin"] = null;
}
//Session.Abandon();
//Session.Clear();
return RedirectToAction("Login", "Home");
}
Use RedirectPermanent if the resource has been moved permanently and will no longer be accessible in its previous location. Most browsers will cache this response and perform the redirect automatically without requesting the original resource again.
Use Redirect if the resource may be available in the same location (URL) in the future.
So in your case Redirect would be the option since this would be hit by any user logging out of your system.
Session.Abandon removes all the objects stored in a Session. If you do not call the Abandon method explicitly, the server removes these objects and destroys the session when the session times out. It also raises events like Session_End
Session.Clear removes all keys and values from the session-state collection.
Think of it like this: Session.Clear can be compared to removing all items from a cart, while Session.Abandon is more like abandoning the entire cart itself.
You can use either of these two methods for destroying or clearing your Session. Currently you are doing a Clear explicitly by assigning your UserName and IsAdmin to null.
I've been searching through some examples here, but could not find what I needed, so I'm posting my question here:
I'm using Form authentication and MVC 4.5.
The problem is following:
I'm emailing the URL to the user and the user needs to click on URL and be able to get redirected to that URL after he was authenticated.
My Login Controller has a method Index that is invoked when user tries to log in:
[HttpPost]
public ActionResult Index(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
try
{
LoginModel lm = LoginModel.AuthenticateUser(model.UserName, model.Password);
if (lm.IsAuthenticated)
{
ApplicationSession.SetUser(lm.User);
FormsAuthentication.SetAuthCookie(model.UserName, false);
if (lm.User.ChangePassword)
{
return Redirect(returnUrl ?? Url.Action("ForceChangePassword", "ChangePassword"));
}
else
{
return Redirect(returnUrl ?? Url.Action("Index", "Details"));
}
}
else
{
if (lm.GroupPermissionMessage.Length > 0)
{
ModelState.AddModelError("", lm.GroupPermissionMessage);
}
else
{
ModelState.AddModelError("", lm.SaveResult.ErrorDescription);
}
return View();
}
}
catch(Exception error)
{
ModelState.AddModelError("", error.Message);
return View();
}
}
else
{
return View();
}
}
The login form has the following definition:
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "LoginForm", returnUrl = Request.QueryString["ReturnUrl"] }))
This is my logic that generates URL for the email:
var queryString = #Url.Action("Index", "Details", new System.Web.Routing.RouteValueDictionary(new { id = model.Ticket.TicketId }), "http", Request.Url.Host);
var ticketUrl = "<a href='"
+ #Url.Action("Index", "Detail", new System.Web.Routing.RouteValueDictionary(new { id = model.Ticket.TicketId, returnUrl = queryString }), "http", Request.Url.Host)
+ "'>Go to your ticket</a>";
I'm expecting Request.QueryString["ReturnURL"] to be equal to the URL I'm opening from the email, so I can redirect to it in my Index method of a controller.
Right now, I'm able to navigate to that URL if I'm already authenticated.
However, if I'm signed off and try to navigate to that URL, Login page is opened first. Then I need to login and should be automatically get redirected to the URL I clicked in my email.
How can I do that?
What am I missing here?
I'm trying to call a method from another controller using RedirectToAction(). But it doesn't work. Could you please explain, what I'm doing wrong?
[HttpPost]
public ActionResult AddToWishList(int id, bool check)
{
var currentUser = WebSecurity.CurrentUserId;
if (currentUser != -1)
{
// ...
}
else
{
return RedirectToAction("Login", "Account");
}
}
I call the method in HTML:
<script>
$(document).ready(function () {
/* call the method in case the user selects a checkbox */
$("#checkbox".concat(#Model.Id)).change(function () {
$.ajax({
url: '#Url.Action("AddToWishList", "Item")',
type: 'POST',
data: {
id: '#Model.Id',
check: this.checked
}
});
});
});
It works if I use:
success: function (result) {
window.location.href = "#Url.Content("~/Account/Login")";
}
But I don't need to navigate to the Login() after every click, only if the user is not authorized. Could you please explain how I can use redirect in the controller?
You can response JavaScript which basically returns JavaScriptResult.
[HttpPost]
public ActionResult AddToWishList(int id, bool check)
{
return JavaScript("window.location='/Account/Login'");
}
To add to #Win's answer - I had a use case where I had a legacy ASPX file in my ASP.NET MVC application. And, I had to navigate to that ASPX page from my MVC action returning ActionResult. So, I did something like this to navigate to that ASPX page from my action. I had to create an absolute URL for navigation.
var myLegacyPageUrl = Request.Url.Scheme
+ "://"
+ Request.Url.Authority
+ Url.RequestContext.HttpContext.Request.ApplicationPath
+ "/mylegacypage.aspx?";
return JavaScript(string.Format("window.location='{0}'", errorPageUrl));
Hope someone finds it useful in case of legacy web pages present in modern MVC website.
My goal is to use the FB login button so that FB users can log into my ASP.NET MVC 3 website. It seems that things have changed recently with the Facebook C# SDK and all the old examples will not work with the new version. I've tried for a day to get them to work... I'm working off of the tutorial Getting Started with the Facebook C# SDK for ASP.NET
Currently when I browse to http://localhost:8033/ it seems to automatically log me in (even after a fresh restart of Chrome) because it shows "my-name uses my-app-name" and shows my picture. I expected it to instead show a FB login button. And when I go to http://localhost:8033/Home/About I get an error that Session["AccessToken"] is null (which makes sense because it's clearly not getting set).
Here's what I have:
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Facebook;
namespace FacebookTest.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
var accessToken = Session["AccessToken"].ToString();
var client = new FacebookClient(accessToken);
dynamic result = client.Get("me", new { fields = "name,id" });
string name = result.name;
string id = result.id;
ViewBag.Message = "Hello id: " + id;
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult FacebookLogin(HttpContext context)
{
var accessToken = context.Request["accessToken"];
context.Session["AccessToken"] = accessToken;
return RedirectToAction("About");
}
}
}
Index.cshtml
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
<p>
To learn more about ASP.NET MVC visit http://asp.net/mvc.
</p>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function () {
FB.init({
//appId: 'YOUR_APP_ID', // App ID
appId: '<MY-NUMBER-REMOVED>', // App ID
status: true, // check login status
cookie: true, // enable cookies to allow the server to access the session
xfbml: true // parse XFBML
});
// Additional initialization code here
FB.Event.subscribe('auth.authResponseChange', function (response) {
if (response.status === 'connected') {
// the user is logged in and has authenticated your
// app, and response.authResponse supplies
// the user's ID, a valid access token, a signed
// request, and the time the access token
// and signed request each expire
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
// TODO: Handle the access token
// Do a post to the server to finish the logon
// This is a form post since we don't want to use AJAX
var form = document.createElement("form");
form.setAttribute("method", 'post');
//form.setAttribute("action", '/FacebookLogin.ashx');
form.setAttribute("action", '/Home/FacebookLogin');
var field = document.createElement("input");
field.setAttribute("type", "hidden");
field.setAttribute("name", 'accessToken');
field.setAttribute("value", accessToken);
form.appendChild(field);
document.body.appendChild(form);
form.submit();
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook,
// but has not authenticated your app
} else {
// the user isn't logged in to Facebook.
}
});
};
// Load the SDK Asynchronously
(function (d) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) { return; }
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
} (document));
</script>
<div class="fb-login-button" data-show-faces="true" data-width="400" data-max-rows="1"></div>
About.cshtml
#{
ViewBag.Title = "About Us";
}
<h2>About</h2>
<p>
#ViewBag.Message
</p>
Can you tell me how to fix this so that a FB login button is displayed, and when clicked it asks the users to do a FB authentication, sends them back, and then my app recognizes them as a logged in user?
As for the Login button, if you are logged in to Facebook prior to visiting your app you will see the faces instead of the login button, the only way to get the Login button back is to go to facebook.com and do a logout or possibly do a facebook logout using the C# SDK. Depending on your requirements this may or may not be what you wanted. There is a bit about Re-Authentication in the SDK documentation if that is what you really want.
I've tweaked your app by removing the submit() and replaced it with an ajax post, The FacebookLogin action was changed and I added some error handling on the About action. Your original app will work but it will automatically redirect to About if you are logged in to Facebook.
Update Added a login link which does not use Javascript, insert appid and appsecret and adjust portnumber accordingly. This was adapted from the server side login sample found here which is far prettier than this code :)
Note The state value being passed in the server side flow should be a unqiue value that you should validate in the ConnectResponse() method, i.e. generate a value in FacebookLoginNoJs and make sure it's the same in ConnectResponse to prevent cross site request forgery
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Facebook;
namespace FacebookTest.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
ViewBag.Message = "Please log in first";
if (Session["AccessToken"] != null)
{
var accessToken = Session["AccessToken"].ToString();
var client = new FacebookClient(accessToken);
try
{
dynamic result = client.Get("me", new { fields = "name,id" });
string name = result.name;
string id = result.id;
ViewBag.Message = "Hello id: " + id + " aka " + name;
}
catch (FacebookOAuthException x)
{
}
}
return View();
}
public void FacebookLogin(string uid, string accessToken)
{
var context = this.HttpContext;
context.Session["AccessToken"] = accessToken;
}
public ActionResult FacebookLoginNoJs()
{
return Redirect("https://www.facebook.com/dialog/oauth?client_id=MY-APPID-REMOVED&redirect_uri=http://localhost:45400/Home/ConnectResponse&state=secret");
}
public ActionResult ConnectResponse(string state, string code, string error, string error_reason, string error_description, string access_token, string expires)
{
if (string.IsNullOrEmpty(error))
{
try
{
var client = new FacebookClient();
dynamic result = client.Post("oauth/access_token",
new
{
client_id = "MY-APPID-REMOVED",
client_secret = "MY-APP-SECRET-REMOVED",
redirect_uri = "http://localhost:45400/Home/ConnectResponse",
code = code
});
Session["AccessToken"] = result.access_token;
if (result.ContainsKey("expires"))
Session["ExpiresIn"] = DateTime.Now.AddSeconds(result.expires);
}
catch
{
// handle errors
}
}
else
{
// Declined, check error
}
return RedirectToAction("Index");
}
}
}
Index.cshtml
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
<p>
To learn more about ASP.NET MVC visit http://asp.net/mvc.
</p>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function () {
FB.init({
//appId: 'YOUR_APP_ID', // App ID
appId: 'MY-APPID-REMOVED', // App ID
status: true, // check login status
cookie: true, // enable cookies to allow the server to access the session
xfbml: true // parse XFBML
});
// Additional initialization code here
FB.Event.subscribe('auth.authResponseChange', function (response) {
if (response.status === 'connected') {
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
var url = '/Home/FacebookLogin';
$.post(url, { uid: uid, accessToken: accessToken }, function (data) {
});
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook,
// but has not authenticated your app
} else {
// the user isn't logged in to Facebook.
}
});
};
// Load the SDK Asynchronously
(function (d) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) { return; }
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
} (document));
</script>
<div class="fb-login-button" data-show-faces="true" data-width="400" data-max-rows="1"></div>
#Html.ActionLink("The NoJs Login", "FacebookLoginNoJs", "Home")
About.cshtml
#{
ViewBag.Title = "About Us";
}
<h2>About</h2>
<p>
#ViewBag.Message
</p>