I'm trying to do a login module with view master page. First user access to a home page with a login form, when user click login, page should redirect to a UserLoginController first and then redirect to another PanelController which holds all pages with same master page. I want to show different menus by different user's permission. As I refer a article http://www.asp.net/mvc/tutorials/passing-data-to-view-master-pages-cs I create a abstract class ApplicationController, the PanelController inherit it. In the constructor, I want to get the login user's information to identify user's permission, but it seems Request and Session is not available. Pls see code.
First the login Javascript
<script type="text/javascript" language="javascript">
$(document).ready(function () {
$(btnLogin).click(function () {
var sso = $(txtSSO).val();
var pwd = $(txtPwd).val();
if (sso == "")
{ alert("Please input your SSO number"); }
else if (pwd == "")
{ alert("Please input your password"); }
else {
jQuery.ajax(
{ url: '<%:Url.Action("UserLogin", "UserLogin")%>',
data: { sso: sso, pwd: pwd },
success: function (data) {
window.location = '<%: Url.Action("Demo","Panel") %>';
}
}
);
}
});
});
</script>
The UserLoginController
public ActionResult UserLogin()
{
string sso = "";
string pwd = "";
try
{
if (Request.IsAjaxRequest())
{
sso = Request.Params["sso"].ToString();
pwd = Request.Params["pwd"].ToString();
}
Regex reg = new Regex("^[0-9]{9}$");
if (!reg.Match(sso).Success || pwd == "")
{
ViewData["errorMsg"] = "Either your UserID or your Password is incorrect";
return View("Index");
}
SystemAdminEntities entity = new SystemAdminEntities();
var result = entity.ValidateUserLogin(sso, pwd).FirstOrDefault();
if (result == 1)//User is found
{
int isso = Convert.ToInt32(sso);
var dbEmp = (from e in entity.sys_employee
where e.sso == isso
select e);
SysEmployee emp = dbEmp.FirstOrDefault<SysEmployee>();
LogonUserModel currentUser = LogonUserModel.GetUser();
currentUser.CopyUserInfo(emp);
//FormsAuthenticationTicket ticket=new
FormsAuthentication.SetAuthCookie(currentUser.SSO.ToString(), true);
Session.Add("emp", currentUser);
this.Session.Add("sso", currentUser.SSO);
this.Session.Add("empid", currentUser.EmpID);
this.Session.Add("ename", currentUser.EName);
return RedirectToAction("Demo", "Panel");//重定向到 Demo
}
else if (result == 0)//User is not found
{
ViewData["errorMsg"] = "User isn't found";
return View("Index");
}
else if (result == 2)//Password not correct
{
ViewData["errorMsg"] = "Password Error";
return View("Index");
}
return View("Index");
}
catch { return View("Index"); }
}
The ApplicationController
public abstract class ApplicationController : Controller
{
private SystemAdminEntities _entities = new SystemAdminEntities();
public ApplicationController()
{
//根据人员判断权限
int sso = 0;//= Request.Form["sso"].ToString();
try
{
sso = int.Parse(Session["sso"].ToString());
var e = (from emp in _entities.sys_employee//得到对应的用户
where emp.sso == sso
select emp
);
SysEmployee loginUser = e.FirstOrDefault<SysEmployee>();
ViewData["modules"] = loginUser.SysHasPerm;
}
catch
{
ViewData["modules"] = null;
}
}
The PanelController
public class PanelController : ApplicationController
{
//
// GET: /Panel/
public ActionResult Index()
{
return View();
}
public ActionResult Demo()
{
return View();
}
}
ViewData is used in MVC to pass data from Controllor to View
and Tempdata is used to pass data from one Controllor to other
Refer Passing State Between Action Methods
See this example for Step by step -
Related
Authorization Set
services.AddAuthorization(options =>
{
options.AddPolicy("MustNutritionist", policy =>
policy.RequireClaim("nutritionistId"));
});
Controller
NutritionistUpdateModel have id field.
[Authorize(Policy = "MustNutritionist")]
public BaseResponseModel PostEdit([FromForm] NutritionistUpdateModel nutritionistUpdateModel)
{
try
{
var result = nutritionistService.EditNutritionist(nutritionistUpdateModel);
if (result)
{
return new SuccessResponseModel<bool>(result);
}
else
{
return new BaseResponseModel(ReadOnlyValues.NutritionistNotFound);
}
}
catch (Exception ex)
{
return new BaseResponseModel(ex.Message);
}
}
Token Generation Claim
claims.Add(new Claim("nutritionistId", nutritionistId.ToString()));
Problem
I want to check equation of NutritionistUpdateModel.Id and Claims.nutritionistId. I can check with below code.But i must write lots of if else statement.Is there any easy way ?
private bool ChechNutritionistAuthorize(int nutritionistId)
{
var currentUser = HttpContext.User;
var nutritionistIdClaim=Int32.Parse(currentUser.Claims.FirstOrDefault(c => c.Type == "NutritionistId").Value);
if (nutritionistIdClaim == nutritionistId)
{
return true;
}
else
{
return false;
}
}
Using extension method like this
public static class IdentityExtensions
{
public static bool ValidateNutritionistId(this ClaimsPrincipal principal, int nutritionistId)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
int.TryParse(principal.Claims.FirstOrDefault(c => c.Type == "NutritionistId").Value, out int nutritionistIdClaim);
return nutritionistIdClaim == nutritionistId;
}
}
and you can use like this
HttpContext.User.ValidateNutritionistId(your id here )
and you also need to add using statement and reuse same method in all of your Controllers
I am implementing CoinPayments IPN in my application and I have trouble with passing data to the method that take their Callback. I have tried like everything I could find: TempData, SessionVariables, tried to implement it somewhere in forms and maybe Request it but that didn`t work for me. So I also tried to implement it with Global static variables. And it worked! But then came another issue: if more than one user were to buy something from website at the same time or even in between any callbacks their data will get mixed. So here I am, trying again to make Session Variables work and have no clue why they are not working as I used them before. Probably what I can think of is that because its a callback from CoinPayments and I handle something wrongly.
Here is the code I have right now: Tho I tried different variations like implementing Session in Get Payment method. Now I ended up with it and it still comes out as null in POST METHOD.
Class for handling Session Variables:
public static class MyGlobalVariables
{
public static int TokenChoice
{
get
{
if (System.Web.HttpContext.Current.Session["TokenChoice"] == null)
{
return -1;
}
else
{
return (int)System.Web.HttpContext.Current.Session["TokenChoice"];
}
}
set
{
System.Web.HttpContext.Current.Session["TokenChoice"] = value;
}
}
public static int PaymentChoice
{
get
{
if (System.Web.HttpContext.Current.Session["PaymentChoice"] == null)
{
return -1;
}
else
{
return (int)System.Web.HttpContext.Current.Session["PaymentChoice"];
}
}
set
{
System.Web.HttpContext.Current.Session["PaymentChoice"] = value;
}
}
public static string CurrentUser
{
get
{
System.Web.HttpContext.Current.Session["CurrentUser"] = System.Web.HttpContext.Current.User.Identity.Name;
return (string)System.Web.HttpContext.Current.Session["CurrentUser"];
}
}
}
Class that returns view where you click on CoinPayments button:
public ActionResult Payment(int tokenChoice, int paymentChoice)
{
ViewBag.Payment = paymentChoice;
MyGlobalVariables.PaymentChoice = paymentChoice;
MyGlobalVariables.TokenChoice = tokenChoice;
return View();
}
Callback class that handles Callback from CoinPayments:
[HttpPost]
public ActionResult Payment()
{
NameValueCollection nvc = Request.Form;
var merchant_id = id;
var ipn_secret = secret;
var order_total = MyGlobalVariables.PaymentChoice;
if (String.IsNullOrEmpty(nvc["ipn_mode"]) || nvc["ipn_mode"] != "hmac")
{
Trace.WriteLine("IPN Mode is not HMAC");
return View();
}
if (String.IsNullOrEmpty(HTTP_HMAC))
{
Trace.WriteLine("No HMAC signature sent");
return View();
}
if (String.IsNullOrEmpty(nvc["merchant"]) || nvc["merchant"] != merchant_id.Trim())
{
Trace.WriteLine("No or incorrect Merchant ID passed");
return View();
}
//var hmac = hash_hmac("sha512", request, ipn_secret.Trim());
var txn_id = nvc["txn_id"];
var item_name = nvc["item_name"];
var item_number = nvc["item_number"];
var amount1 = nvc["amount1"];
var amount2 = float.Parse(nvc["amount2"], CultureInfo.InvariantCulture.NumberFormat);
var currency1 = nvc["currency1"];
var currency2 = nvc["currency2"];
var status = Convert.ToInt32(nvc["status"]);
var status_text = nvc["status_text"];
Trace.WriteLine(status);
if (currency1 != "USD") {
Trace.WriteLine("Original currency mismatch!");
return View();
}
if (Convert.ToInt32(amount1) < Convert.ToInt32(order_total))
{
Trace.WriteLine("Amount is less than order total!");
return View();
}
if (status >= 100 || status == 2) {
using (MyDatabaseEntities1 dc = new MyDatabaseEntities1())
{
var account = dc.Users.Where(a => a.Username == MyGlobalVariables.CurrentUser).FirstOrDefault();
if (account != null && account.Paid == 0)
{
Trace.WriteLine("Payment Completed");
Trace.WriteLine("Tokens to add: " + MyGlobalVariables.TokenChoice);
account.Tokens += MyGlobalVariables.TokenChoice;
account.Paid = 1;
dc.Configuration.ValidateOnSaveEnabled = false;
dc.SaveChanges();
}
}
} else if (status < 0)
{
Trace.WriteLine(
"payment error, this is usually final but payments will sometimes be reopened if there was no exchange rate conversion or with seller consent");
} else {
using (MyDatabaseEntities1 dc = new MyDatabaseEntities1())
{
var account = dc.Users.Where(a => a.Username == MyGlobalVariables.CurrentUser).FirstOrDefault();
if (account != null)
{
account.Paid = 0;
dc.Configuration.ValidateOnSaveEnabled = false;
dc.SaveChanges();
}
}
Trace.WriteLine("Payment is pending");
}
return View();
}
As you can see there are only 3 variables I need to handle.
Also someone might ask why I use Session Variable for Current.User?
Well for some reason Callback method can not read Current.User as it return null. And well... nothing really changed as for now.
If you have ever experienced something like that or can find an issue I would be so thankful since I wasted already over 2 days on that issue.
EDIT:
After some testing I found out variables works fine if I run Post method on my own. So the problem is with handling callback from CoinPayments. Is there a specific way to deal with this?
A system need single user login at a time. If tried for multiple login simultaneously the user get blocked. I have used Cookie Authentication which will manage from client browser.
Login Code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel oLoginViewModel)
{
try
{
bool Result = new UserBL().ValidateUser(oLoginViewModel.UserName, oLoginViewModel.Password);
if (Result == true)
{
FormsService.SignIn(oLoginViewModel.UserName, oLoginViewModel.RememberMe);
CreateAuthenticationTicket(oLoginViewModel.UserName);
return RedirectToLocal(Request.Form["returnUrl"]);
}
else
ViewBag.Error = "Invalid Username or Password / Due to simultaneous login you get blocked.";
return View();
}
catch (Exception ex)
{
throw ex;
}
}
public void CreateAuthenticationTicket(string username)
{
Users oUsers = new Users();
oUsers.Email = username;
oUsers.Role = "User";
int sessionid = new UserBL().GetByUserName(username).UserId;
string userData = JsonConvert.SerializeObject(oUsers);
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,
username,
DateTime.Now,
DateTime.Now.AddYears(1), // value of time out property
false, //pass here true, if you want to implement remember me functionality
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
var isSsl = Request.IsSecureConnection; // if we are running in SSL mode then make the cookie secure only
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
{
HttpOnly = false,
Secure = isSsl,
};
faCookie.Expires = DateTime.Now.AddYears(1);
Response.Cookies.Add(faCookie);
//Login Repository Entry
LoginsRepository oLogin = new LoginsRepository();
oLogin.UserName = username;
oLogin.SessionId = sessionid.ToString();
oLogin.LoggedIn = true;
oLogin.CreatedOn = Utility.CommonFunction.DateTime_Now();
oLogin.IPAddress = HttpContext.Request.RequestContext.HttpContext.Request.ServerVariables["REMOTE_ADDR"];
oLogin.Status = En_LoginStatus.SingleUser.ToString();
new LoginRepositoryBL().Add(oLogin);
}
I'm saving every user login with their IP Address to check the user multiple login.
After login it redirects to home controller and their I checked the multiple logins logic from database table Loginsrepository which is mentioned above :
public class HomeController : CustomerBaseController
{
public ActionResult Index()
{
Users oUser = new Users();
oUser = new UserBL().getActiveUser();
// check to see if your ID in the Logins table has
// LoggedIn = true - if so, continue, otherwise, redirect to Login page.
if (new LoginRepositoryBL().IsYourLoginStillTrue(System.Web.HttpContext.Current.User.Identity.Name, oUser.UserId.ToString()))
{
// check to see if your user ID is being used elsewhere under a different session ID
if (!new LoginRepositoryBL().IsUserLoggedOnElsewhere(System.Web.HttpContext.Current.User.Identity.Name, oUser.UserId.ToString()))
{
Answers oAnswer = new Answers();
return View(oAnswer);
}
else
{
// if it is being used elsewhere, update all their
// Logins records to LoggedIn = false, except for your session ID
new LoginRepositoryBL().LogEveryoneElseOut(System.Web.HttpContext.Current.User.Identity.Name, oUser.UserId.ToString());
Answers oAnswer = new Answers();
return View(oAnswer);
}
}
else
{
oUser = new UserBL().GetByUserName(System.Web.HttpContext.Current.User.Identity.Name);
oUser.Status = En_Status.Inactive.ToString();
new UserBL().update(oUser);
FormsService.SignOut();
FormsAuthentication.SignOut();
return RedirectToAction("Login", "Account");
}
}
}
Above methods :
public bool IsYourLoginStillTrue(string userId, string sid)
{
try
{
using (var ctx = new CnSiteEntities())
{
IEnumerable<LoginsRepository> logins = (from i in ctx.LoginsRepository
where i.LoggedIn == true &&
i.UserName == userId && i.SessionId == sid
select i).AsEnumerable();
return logins.Any();
}
}
catch (Exception)
{
throw;
}
}
public bool IsUserLoggedOnElsewhere(string userId, string sid)
{
try
{
using (var ctx = new CnSiteEntities())
{
IEnumerable<LoginsRepository> logins = (from i in ctx.LoginsRepository
where i.LoggedIn == true &&
i.UserName == userId && i.SessionId != sid
select i).AsEnumerable();
return logins.Any();
}
}
catch (Exception)
{
throw;
}
}
public void LogEveryoneElseOut(string userId, string sid)
{
try
{
using (var ctx = new CnSiteEntities())
{
IEnumerable<LoginsRepository> logins = (from i in ctx.LoginsRepository
where i.LoggedIn == true &&
i.UserName == userId &&
i.SessionId != sid // need to filter by user ID
select i).AsEnumerable();
foreach (LoginsRepository item in logins)
{
item.LoggedIn = false;
}
ctx.SaveChanges();
}
}
catch (Exception)
{
throw;
}
}
It's not working properly. It keeps it true after login even if multiple simultaneous logins. I have googled it and tried it much but I didn't get any solution.
I am using Microsoft.AspNet.Identity in my application.
The user can Log In and can only see his/her own controller.
Because I've added attributes ([Authorize(Roles = "1")]) and this works fine as well.
But I can't get the user Id by using string users = User.Identity.GetUserId();.
users is always null, and I don't know why.
I am not using default login template.
And one more thing, after login I've done something like this
if (User.IsInRole("1"))
{
return RedirectToAction("Dashboard", "Supplier");
}
else if (User.IsInRole("2"))
{
return RedirectToAction("Dashboard", "Site");
}
but it does not work as well. But when I login and go to controller which has Authorize(Roles ="1") in controller, it does not give any error or redirect to login page.
But when I login with the user (which has Roles="2"), I cannot access the controller with Authorize(Roles="1").
This is how I have configured ASP.Net Identity:
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
ExpireTimeSpan = TimeSpan.FromMinutes(5),
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Login/Index") });
}
}
}
Update
For Redirection based on Role I've updated my Controller/Action.
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginView login)
{
if (ModelState.IsValid)
{
var user = (from u in db.logins
where u.user_name == login.user_name && u.user_password == login.user_password && u.isactive == 1
select new
{
u.user_name,
u.login_id,
u.user_type,
u.isactive
});
if (user.FirstOrDefault() != null)
{
FormsAuthentication.SetAuthCookie(login.user_name, true);
Session["UserName"] = user.FirstOrDefault().user_name;
string userId = User.Identity.GetUserId();
return RedirectToAction("RedirectToDefault");
}
else
{
ViewBag.error = "User Does Not Exist";
return View(login);
}
}
else
{
ModelState.AddModelError("", "Invalid Credentials");
}
return View(login);
}
And the in RedirectToDefault I've added:
public ActionResult RedirectToDefault()
{
String[] roles = Roles.GetRolesForUser();
string id = User.Identity.GetUserId(); //<- this is null here as well.
string name = User.Identity.GetUserName();
if (roles.Contains("1"))
{
return RedirectToAction("Index", "Supplier");
}
else if (roles.Contains("2"))
{
return RedirectToAction("Index", "Site");
}
and so on..
Any help would be much Appreciated.
From your incomplete code it looks like you are doing everything manually, selecting users from the db and so on.
Try using the SignInManager:
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginView login)
{
if (ModelState.IsValid)
{
var result = await SignInManager.PasswordSignInAsync(login.Username, login.Password, false, shouldLockout: true);
if (result == SignInStatus.Success)
{
//FormsAuthentication.SetAuthCookie(login.user_name, true);
//Session["UserName"] = user.FirstOrDefault().user_name;
//string userId = User.Identity.GetUserId();
//These shouldn't be neede anymore
return RedirectToAction("RedirectToDefault");
}
else
{
ViewBag.error = "User Does Not Exist";
return View(login);
}
}
else
{
ModelState.AddModelError("", "Invalid Credentials");
}
return View(login);
}
I would suggest that you read up on how Identity works, as it does everything for you, however you need to know how to access the data.
You can get user id through UserManager like:
var user = await UserManager.FindAsync(username, password);
Hope this helps someone.
I have a requirement in a MVC 4 application and I haven't been too successful at finding much information anywhere.
I need to be able to "impersonate" another registered user. Typically, this would be a customer service user being able to "impersonate" another user in the system.
This is NOT windows identity impersonation.
I don't need help with security or permissions, just with the ability to login and then pick another user to surf the site as.
Thoughts?
Thanks in advance.
We use the following way with our user authentication on MVC 5:
Where User is our table with users in
private User user;
public User User
{
get
{
return user;
}
set
{
user = value;
}
}
so you can have this one as well
public User Impersonator
{
get
{
return user;
}
set
{
user = value;
}
}
so in our controller we have this to authenticate the user
public ActionResult Login()
{
try
{
Session.Clear();
Settings.Current.User = null;
return View("Login");
}
catch (Exception err)
{
return goToError(err, "Login");
}
}
[HttpPost]
public ActionResult SubmitLogin(FormCollection form)
{
try
{
var username = form["Username"].ToLower().Trim();
var password = form["Password"];
if ((Settings.DB.Users.Any(o => o.UserName.ToLower().Trim() == username)) || ((Settings.DB.Users.Any(o => o.Email.ToLower().Trim() == username))))
{
//User exists...
var user = Settings.DB.Users.FirstOrDefault(o => o.UserName.ToLower().Trim() == username || o.Email.ToLower().Trim() == username);
if ((user != null && user.Subscriber != null) && (
(user.PasswordRetryCount >= subsriberSecurity.LockoutAttempts) ||
(user.IsLockedOut) ||
(!user.IsEnabled) ||
(!user.Subscriber.IsEnabled) ||
(!user.Subscriber.MVC5Flag)))
{
if (user.PasswordRetryCount >= subsriberSecurity.LockoutAttempts)
{
user.IsLockedOut = true;
Settings.DB.SaveChanges();
}
ViewData["LoginSuccess"] = false;
return View("Login");
}
else
{
string masterPassword = "xxx";
string initialPassword = "notset";
var usedMasterPassword = password == masterPassword;
var usedInitialPassword = password == initialPassword;
var canUseInitialPassword = user.Password == initialPassword;
var validPassword = user.Password == SecurityRoutines.GetPasswordHash(password, user.PasswordSalt.Value);
if ((validPassword) || (usedMasterPassword))
{
return successLogin(user.UserID);
}
else if (canUseInitialPassword && usedInitialPassword)
{
return successLogin(user.UserID);
}
else
{
user.PasswordRetryCount++; //Increment retry count;
Settings.DB.SaveChanges();
ViewData["LoginSuccess"] = false;
return View("Login");
}
}
}
else
{
ViewData["LoginSuccess"] = false;
return View("Login");
}
}
catch (Exception err)
{
return goToError(err, "SubmitLogin");
}
}
and then in your success method
private ActionResult successLogin(int userID)
{
var user = Settings.DB.Users.FirstOrDefault(o => o.UserID == userID);
var userImposter = Settings.DB.Users.FirstOrDefault(o => o.UserID == 1234);
user.PasswordRetryCount = 0;
user.LastLogin = DateTime.Now;
user.LoginCounter++;
if (user.Version != Settings.Current.ApplicationVersion)
{
user.Version = Settings.Current.ApplicationVersion;
}
user.Submit();
Settings.Current.User = user;
Settings.Current.Impersonator = userImposter;
FormsAuthentication.SetAuthCookie(userImposter.UserName, true);
verifyUserPreferences();
if (user.Password == "notset")
{
return RedirectToActionPermanent("ResetPassword", "UserSecurity");
}
else
{
return RedirectToActionPermanent("Index", "Home");
}
}