Ember + web api single page redirect - api

I have a asp.net mvc web api app with ember and simplemembershipprovider. I am using the ember template and with it, ember app is created upon user successfully logged in in the home controller.
public ActionResult Index(string returnUrl)
{
if (User.Identity.IsAuthenticated)
{
return View("App");
}
ViewBag.ReturnUrl = returnUrl;
return View();
}
Sometimes user would click a link in an email with an id when visiting the site, if the url includes an id, upon successful login, I want to redirect user to a detail page base on the provided id in the url. An example would be http://siteURL.com/#/product/1412 . I am having a hard time figuring out how to do this. Since this is a client side ember route, MVC does not differentiate between this route and http://siteURL.com so it just ignores the redirect request. Here is what I have tried.
assign the url in the login controller - nothing happens after json data is returned, stays in the login page and never hit the HomeController even though user is not authenticated.
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
returnUrl = "http://siteURL.com/#/product/1412";
return Json(new { success = true, redirect = returnUrl });
use response redirect. Same as #1
Response.Redirect(returnUrl);
Assigned url in home controller, same as above.
if (User.Identity.IsAuthenticated)
{
returnUrl = "http://siteURL.com/#/product/1412";
return View("App");
}
ViewBag.ReturnUrl = returnUrl;
return View();

Most browsers don't even send the # up to the server, so you won't have it to redirect. Here's a few options
Don't use the hash, not every browser supports it, http://emberjs.com/guides/routing/specifying-the-location-api/
Give them a fake address that redirects, http://siteURL.com/Redirect/product/1412
inject that url into some js on the page that redirects on load

Related

Net Core - Cookie SameSite

I found the problem in my project. The problem is that the cookie is not saved when the user is logged in via the iframe. Cookies are saved when you log in to the site normally, that is, directly through the domain. There are 2 different problems for me right now:
When logging into the site directly (www.example.com), the relevant cookie is saved. But this cookie is saved as Lax. I want it to be saved as none.
If there is no direct login to the site before, if you want to log in from within the iframe, the cookie is not saved. I want to create cookies on logins made via iframe.
I did not perform anything on the cookie. I guess SignAsync() creates the relevant cookies automatically. I am also attaching my codes inside the Account Controller.
public IActionResult Login(string returnurl)
{
return View(new LoginViewModel {ReturnUrl=returnurl, IsPersistent=true });
}
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model)
{
var result = await signInManager.PasswordSignInAsync(model.Username, model.Password, model.IsPersistent, true);
if (result.Succeeded)
{
return Redirect(model.ReturnUrl ?? "/");
}
else
{
ModelState.AddModelError("","Invalid User Login");
return View(model);
}
}
I also tried the solutions in the links below but it didn't work for me. Maybe I have applied these solutions incorrectly.
https://learn.microsoft.com/tr-tr/aspnet/core/security/samesite/rp31?view=aspnetcore-3.1&viewFallbackFrom=aspnetcore-6.0
https://learn.microsoft.com/tr-tr/aspnet/core/security/samesite?view=aspnetcore-6.0
And here is a photo:
Cookie View with Cookie Editor

How to overwrite post logout redirect url

I am using IdentityServer3 and i have ASP.NET Core as Client application.
Here is my LoggOff action method
[HttpPost]
public async Task LogOff()
{
await Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.SignOutAsync(HttpContext, CookieAuthenticationDefaults.AuthenticationScheme);
await Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.SignOutAsync(HttpContext, OpenIdConnectDefaults.AuthenticationScheme);
}
When user logs out i see the following redirects in fiddler
GET /identity/connect/endsession?post_logout_redirect_uri=https%3A%2F%2Flocalhost%3A44352%2Fsignout-callback-oidc&state=XXXXXX&x-client-SKU=XXXXXX&x-client-ver=5.3.0.0 HTTP/1.1
GET /identity/logout?id=XXXXXXXXXX
GET /identity/connect/endsessioncallback?sid=XXXXXXX
and eventually in browser url is set to /identity/logout?id=XXXXXXXXXX. These are identity server's URL not Client Application URL.
This is working as expected when logoff button invokes LogOff action method.
Now i have a requirement. When user goes to AccessDenied page i want to logoff user first,and then redirect to AccessDenied view. The AccessDenied page is in ClientAppliction. So i have another action method that invokes SingnOut and set RedirectUri
[HttpGet]
public async Task AccessDenied()
{
await Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.SignOutAsync(HttpContext, CookieAuthenticationDefaults.AuthenticationScheme);
await Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.SignOutAsync(HttpContext,
OpenIdConnectDefaults.AuthenticationScheme,
new Microsoft.AspNetCore.Authentication.AuthenticationProperties()
{
RedirectUri = "Account/AccessDenied"
});
}
This is not working. User still goes to identity/logout instead of AccessDenied. Looks like it is not setting post logout redirect uri.
Its not a typo that you forgot to prefix the url with / ?
like
RedirectUri = "/Account/AccessDenied"
instead of
RedirectUri = "Account/AccessDenied"

Customise Behaviour On Authorize Failed

I have successfully implemented group based authorization in an MVC application by using the [Authorize(Roles = "Admin")] tags in my controller.
However, the default behaviour when a user requests a page they are not authorized to view is to redirect them to the login page. This far from intuitive, and causes too much confusion amongst users who will repeatedly try to login.
Instead I would like to display a custom screen, or at the very least have a message display on the login screen stating that they are already logged in, but with insufficient privileges.
A User.Identity.IsAuthenticated tag exists, which can be used in the base logic, but there doesn't appear to be a similar IsAuthorised tag.
How can this behaviour be implemented?
I believe you have already partly solved your problem. This because because when authorization fails, the user will be redirected to login page. Verify if the user is authenticated before displaying the login view. If they are authenticated re-direct them to appropriate page instead.The code snippet below will not display login view if the user is authenticated and the cookie has not expired. They will be redirected to "DashboardOrSomeOtherView.cshtml" instead
[HttpGet]
public ActionResult Login(string returnUrl)
{
// Before showing login view check if user is authenticated.
// If they are redirect to suitable page,
// and print appropriate message
if (ControllerContext.HttpContext.User.Identity.IsAuthenticated)
{
// You can even use TempData as additionally, to hold data here and check in
//the view you redirect to if it is not null and is true ,
// then they are authenticated and show some message,
// e.g. You have been redirected here because you do not
// have authorization to view previous page.
TempData["UserAlreadyAuthicated"] = true;
return RedirectToAction("DashboardOrSomeOtherView");
}
// If they are not authenticated , show them login view
return View();
}
In the DashboardOrSomeOtherView
<div>
<h1>DashboardOrSomeOtherView</h1>
#{
if(TempData["UserAlreadyAuthicated"] != null && TempData["UserAlreadyAuthicated"].ToString().ToLower() == "true")
<div>You have been redirected here because of inadequate authorization</div>
}
</div>

How am I supposed to use ReturnUrl = ViewBag.ReturnUrl in MVC 4

I'm working on 'ASP.NET MVC 4' application. I'm using/learning SimpleMembershipProvider and try to stick to the default logic created by VS2012 with the Internet template (if I'm not mistaken, the one with 'SimpleMembershipProvider' out of the box).
I'm stuck at the AccountController where I just can't figure put how exactly I can use this method:
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
From what I understand the whole idea is to get redirected to the location from where you've decided to log in (exactly what I want to accomplish). I took a look at how it's used in the view :
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl }))
Look for a place where actually ViewBag.ReturnUrl is set with some value and I only got this method here:
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
and I'm getting pretty confused about how exactly I'm supposed to get the location/url. I set some breakpoints and I have never seen returnUrl to be something different from null which in this scenario seems pretty logical to me since it doesn't get value anywhere (unless I miss something of course).
So I really can't figure out how this work. I post the above just to show that I tried to do my homework, I investigate as much as I could but I didn't found an answer so I ask here. Could you provide explanation/example on how this actually work?
When using forms authentication and the user is not authenticated or authorized the ASP.NET security pipeline will redirect to the login page and pass as a parameter in the query string the returnUrl equal to the page that redirected to the login page. The login action grabs the value of this parameter and puts it in the ViewBag so it can be passed to the View.
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
The View then stores this value in the form as shown by this line of code in the View.
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl }))
The reason it is stored in the View is so that when the user does a Submit after entering their user name and password, the controller action that handles the post back will have access to this value.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
If the model state is valid and they are authenticated by calling the WebSecurity.Login method then it calls the method RedirectToLocal with the value of returnUrl which came from the View, which originally came form the login action that created the View.
The returnUrl value will be null if the user is not redirected to the login page as is the case when they just click on the login link at the top of the page in the default layout. In this case the user will be redirected to the home page after successful login. The whole purpose of the returnUrl is to automatically send the user back to the page they were trying to access before they were authenticated/authorized.
That's because the default ASP.NET MVC template is using Forms authentication, and controllers are decorated with [Authorize] attribute:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
[Authorize]
public class AccountController : Controller
{
//...
}
That means that if the user is not authenticated it will be redirected to the logon page defined in the LoginUrl attribute of the forms element.
During the redirection, FormsAuthentication which is an HttpModule will append the url which was requested in the query string automatically.
So if you navigate to /Account/Login, you wont get anything in the query string since it is decorated with [AllowAnonymous] attribute.
But if you navigate to /Account/Manage you'll notice that the returnUrl in the query string becomes /Account/Manage (/Account/Login?ReturnUrl=%2fAccount%2fManage)
So you are not setting the returnUrl, the framework does it for you, you just use it in the AccountController to know where to redirect the user after he is authenticated.
When an unauthenticated user tries to get into a section of your application which requires authentication, then returnUrl comes into the picture. The Url requested by the unauthenticated user is basically stored in returnUrl.
You can go through the PluralSight tutorial: Building Applications with ASP.NET MVC 4

How do a website post to user's twitter status ?

I have a c# mvc 4 web site,I've created a twitter app on https://dev.twitter.com/apps.
from there I want to have a button on homepage to redirect the user to my app on twitter to confirm access information. after that the web site will do a post to the user twitter saying .. "I've joined the new web site .. "
I'm managed doing the part to redirect the user to allow access information :
public ActionResult Login()
{
try
{
string url = "";
string xml = "";
oAuthTwitter oAuth = new oAuthTwitter();
if (Request["oauth_token"] == null)
{
//Redirect the user to Twitter for authorization.
//Using oauth_callback for local testing.
Response.Redirect(oAuth.AuthorizationLinkGet());
}
Now I need to make a post on the user status
How do I do that ? is there a c# wrapper for Twitter API 1.1 ?
It's a multi-step process. First you direct the user to Twitter to authorize the app, and in this redirect you supply Twitter with a call-back URL in your website. Twitter will then direct the user back to that URL with (or without if they refuse access) a code that you would use to post to Twitter on the user's behalf.
You can simplify a lot of this by using something like TweetSharp, and the code might look something like this:
// This is when the user clicks on a link on your site to use your Twitter app
public ActionResult Twitter()
{
// Here you provide TweetSharp with your AppID and AppSecret:
var service = new TwitterService(AppID, AppSecret);
// Provide TweetSharp with your site's callback URL:
var token = service.GetRequestToken("http://www.yoursite.com/Home/TwitterCallback");
// Get the fully-formatted URL to direct the user to, which includes your callback
var uri = service.GetAuthorizationUri(token);
return Redirect(uri.ToString());
}
// When twitter redirects the user here, it will contains oauth tokens if the app was authorized
public ActionResult TwitterCallback(string oauth_token, string oauth_verifier)
{
var service = new TwitterService(AppID, AppSecret);
// Using the values Twitter sent back, get an access token from Twitter
var accessToken = service.GetAccessToken(new OAuthRequestToken { Token = oauth_token }, oauth_verifier);
// Use that access token and send a tweet on the user's behalf
service.AuthenticateWith(accessToken.Token, accessToken.TokenSecret);
var result = service.SendTweet(new SendTweetOptions { Status = "I've joined the new web site .. " });
// Maybe check the "result" for success or failure?
// The interaction is done, send the user back to your app or show them a page?
return RedirectToAction("Index", "Home");
}