How to get OAuth working on MVC4 mobile - asp.net-mvc

I have been struggling to get OAuth to work on my MVC4 mobile application.
I basically
Created an MVC4 Mobile application
Created an MVC4 Web application
Copied the AccountController, AccountModel, InitializeSimpleMembershipAttribute and all account views into my MVC4 Mobile application
Enabled Google and Facebook OAuth providers
I also ensured RoleManager was initialized according to simplemembershipprovider-not-working, although I do not think that was important. ( I needed it for some role-based security I was testing)
Disabled ajax ( I think) by setting data-ajax="false":
using (Html.BeginForm("ExternalLogin", "Account",new RouteValueDictionary { { "ReturnUrl", ViewBag.ReturnUrl } }, FormMethod.Post, new Dictionary<string, object> { { "data-ajax", false } })) (This did not seem to have any effect on the page - so I may be doing something wrong here...)
I can get to the LogIn view /Account/Login, and when I click the google button, the debugger breaks into public ActionResult ExternalLogin(string provider, string returnUrl)
However - the public ActionResult ExternalLoginCallback(string returnUrl) is never hit.
Visually, I get the jquery mobile "page loading" animation - then I get "Error Loading Page"
I have two questions:
How can I get more information when I try to figure out what happens?
How can I get OAuth working on my MVC4 mobile site?
BTW: Both sites target .Net4.0

OK - so I figured out the answer - the cuplrit was indeed the ajax in jQuery mobile.
I modified my _layout.cshtml so that it can render a custom script after loading jQuery, but before loading jQuery mobile:
#Scripts.Render("~/bundles/jquery","~/scripts/RemoveHashFromWindowLocation")
#RenderSection("beforeJqueryMobile", required: false);
#Scripts.Render( "~/bundles/jquerymobile")
#RenderSection("scripts", required: false)
Then I modified my Login.cshtml so that it contains the section:
#section BeforeJqueryMobile {
#Scripts.Render("~/scripts/disable-ajax.js")
}
And finally, I added the following to my scripts folder:
disable-ajax.js:
$(document).bind("mobileinit", function () {
$.mobile.ajaxEnabled = false;
});
RemoveHashFromWindowLocation.js: (Thanks to Facebook Oauth Login With Jquery Mobile #_=_)
if (window.location.hash == "#_=_")
window.location.hash = "";
Voila - OAuth working with jQuery mobile. :-)

The above answer from espenalb does work if your site loads directly to the login page, however if you have say a home page and then and a link to the login page(which uses the same layout), you will get an error loading page when you click one of the social login buttons.
To fix this add
<script>
$('#login-link').live("click", function () {
$.mobile.ajaxEnabled = false;
});
</script>
to the bottom of your mobile layout page, this will attach an event handler that will disable ajax to the login link.

Related

Partial View Link on MVC LoginPage not working (User not logged-in/Authorized yet)

I am working on a website in ASP.NET MVC and working on LoginPage. On the LoginPage, we also have 'Forgot Password' link and clicking that link opens a Modal-popup (bootstrap) with content being returned as PartialView.
Problem I am facing is, when I click on 'Forgot Password' link on the page, Index method of Login controller gets called instead of ForgotPassword related method which results in LoginPage being returned in modal popup.
[AllowAnonymous]
[System.Web.Services.WebMethod()]
public ActionResult ForgotPassword()
{
return PartialView("_ForgotPassword");
}
It seems like some sort of authentication issue because if I login using our old Login Page (it's an .aspx page) and then try to manually go to a new ASP.NET MVC page, all the link with partialView on login Page works fine.
Anyone else had this issue? any pointer would be appreciated.
Thanks
Edit 1: Javascript used to call modal popup
function AttachPopup() {
$('.modal-popup').click(function (event) {
event.preventDefault();
event.stopImmediatePropagation();
var url = $(this).attr('data-content-url');
var modalId = $(this).attr('data-target-model');
var target = $(this).attr('data-target-content');
$.ajax({
url: url,
type: 'POST',
datatype: "json",
cache: false,
traditional: true,
success: function (data) {
$(target).empty();
$(target).append(data);
$(modalId).modal('show');
}
});
});
}
url comes correct but still index is called.
When the AllowAnonymous attribute, the onAuthorization method of AuthorizeAttribute simply ignores authorization and authentication checking. Even if you had a global authorization filter. It should still work. A user had a similar issue. Please check out this link
As mentioned, I was converting an aspx website to MVC. In Web.config, we had
<authorization>
<deny users="?" />
</authorization>
This was taking precedence over MVC [AllowAnonymous] attribute. Commenting out above code, fixed my problem.
Word of caution: When you do that, do check that your website is secure with [Authorize] attribute

.NET Core MVC/Azure AD - 302 Found when making an ajax request

I am using Azure AD along with asp.net core mvc. The following code is the same with a default MVC project generated with Work or School Accounts authentication.
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
Everything works just fine for the most time. The app is basically a notepad. A user logs in and adds notes/tasks. Everything after logging in is done using ajax requests. After some time the app stops working because there is a need for authentication again. Note that if I refresh the page everything is working again.
Am I doing this right? Am I missing something or this kind of use case is not supported.
Should I just create a javascript function that will auto refresh the page after some time?
Should I just create a javascript function that will auto refresh the page after some time?
You could try to create a hidden iframe in all the templates used by the Web App to make automatic calls to a MVC controller method that forces a call to renew the authentication data on a regular basis.
This is achieved very easily by configuring an automatic javascript process in the front-end executed in a loop on a regular basis of 45'. This value could be configured or extracted from a configuration file too. The only key condition is that it must be less than one hour.
Here is the simplified example code related to MVC Controller:
/* Action method, inside "Account" controller class, to force renewal of user authentication session */
public void ForceSignIn()
{
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" },
OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
And here is the simplified example HTML and javascript code employed to call silently in a hidden iframe to MVC Controller:
<iframe id="renewSession" hidden></iframe>
<script>
setInterval( function ()
{ #if (Request.IsAuthenticated) {
<text>
var renewUrl = "/Account/ForceSignIn";
var element = document.getElementById("renewSession");
element.src = renewUrl;
</text>
}
},
1000*60*45
);
</script>
For more details, you could refer to this article which get the similar situation with you.
I found a simple solution by accident. My goal was to hit a check endpoint every minute and If I get a 302 status code I would redirect the user to the authentication page.
public IActionResult Check()
{
return Ok(new { });
}
I left the developer tools open and noticed that every 30 mins I get a bigger response.
And this actually refreshes the cookie and as a result there is no need to redirect the user.
So to sum up someone needs to do this check every 40-50 minutes because the expiration is set to ~1 hour by default.

MVC receive post from another website - Chrome says Post Cancelled

I am posting via a plain html text file on c:\ drive into my mvc website running on my machine:
<body>
<a id="testPost" href="./post_files/post.htm">test post</a>
<script type="text/javascript">
$("#testPost").click(function () {
$.post("http://hml.backend/Helix/Authorisation",
{
ClientIP: "192.168.20.34"
}, function (resultData) {
alert(resultData);
});
return false;
});
the controller is setup thus:
[HttpPost]
public ActionResult Authorisation(string ClientIP)
{
string result = _videoSecurityService.CheckHelixAuthorisation(ClientIP);
return Content(result);
}
The controller event gets hit in debug and there is no exception but Chrome says
'POST: Cancelled' in the debug window
Any ideas why?
This is a cross domain call and is not allowed in a lot of browsers, since it's a possible security risk. You could try to redirect your call on the server-side. (make the call to your own application and handle the request-response to the other website there)

Hash navigation problem while using jquery mobile with asp.net mvc2

I am looking to standardize the processing of ajax #anchors at the server side, using MVC.
Before a controller action is invoked I want to convert every request with ajax anchors into a request without ajax anchors, so that the controller code does not know there were anchors in the request:
For example:
1) /user/profile#user/photos should be treated as /user/photos
2) /main/index#user/profile/33 should be treated as /user/profile/33
What is the best technique in MVC to accomplish that?
This should necessarily be done on the client side, probably using jquery as everything that follows the # sign is never sent to the server.
I too struggle with same issue and I solved this problem after looking at Visual Studio 11 Developer Preview template code. I added following code in my _layout.cshtml, please note we must load jquery.mobile*.js file after following script tag:
<script type="text/javascript">
$(document).bind("mobileinit", function () {
// As of Beta 2, jQuery Mobile's Ajax navigation does not work in all cases (e.g.,
// when navigating from a mobile to a non-mobile page, or when clicking "back"
// after a form post), hence disabling it. http://jquerymobile.com/demos/1.0a3/#docs/api/globalconfig.html
#{
if (ViewBag.JqueryMobileAjaxEnabled != null && ViewBag.JqueryMobileAjaxEnabled == true)
{
#: $.mobile.ajaxEnabled = true;
}
else
{
#: $.mobile.ajaxEnabled = false;
}
}
});
</script>
**<script src="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.js"></script>**

Redirect to an ASP.NET MVC page problem after POST request from Silverlight

In an ASP.NET MVC application I have a CartController with this AddToCart action:
public RedirectToRouteResult AddToCart(Cart cart, decimal productId,
string returnUrl)
{
Product product = productsRepository.Products
.FirstOrDefault(p => p.prodID == productId);
cart.AddItem(product);
return RedirectToAction("Index", new { returnUrl });
}
When a user submits a POST request ("Add to Cart" button) to this action from a plain ASP.NET MVC view, everything goes well: the Product is added to the Cart and the user is automatically redirected to a Cart/Index page.
If the product is submitted from a Silverlight app (which is inside an ASP.NET MVC view) it is successfully added to the Cart as well, but the there is no redirection in this case.
What is the problem? Maybe it is due to the fact that all requests from a Silverlight are asynchronous (if I'm not mistaken), and the request from a general ASP.NET MVC view is synchronous by nature? How it can affect the redirection?
In any case, how this problem could be solved?
Edited (added):
My code for sending a post request from a Silverlight app:
//first build a "paramstring" in the format "productId=126504" and then post it using this
WebClient wc = new WebClient();
wc.Headers["Content-type"] = "application/x-www-form-urlencoded";
wc.UploadStringAsync(new Uri("http://localhost:10930/Cart/AddToCart"), "POST", paramstring, "http://localhost:10930/Products");
The WebClient you are using to send the POST request will automatically follow the redirects performed on the server and return the HTML and everything ends in the success callback. If you want to redirect the user browser to this page you shouldn't use WebClient. You need javascript to submit a <form>. Silverlight allows you to execute javascript, so you could use it to dynamically generate and submit a form, or if the form already exists in the DOM set the values of the input fields and submit it.
Here's an example of how you could do this. Add the following javascript function to the same page hosting the Silverlight application:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
function addToCart(productId, returnUrl) {
var form = $(document.createElement('form'))
.attr('action', '/products/addtocart')
.attr('method', 'post')
.append(
$(document.createElement('input'))
.attr('type', 'hidden')
.attr('name', 'productId')
.val(productId)
)
.append(
$(document.createElement('input'))
.attr('type', 'hidden')
.attr('name', 'returnUrl')
.val(returnUrl)
);
$('body').append(form);
form.submit();
}
</script>
And then inside your Silverlight application whenever you decide to invoke the POST action:
HtmlPage.Window.Invoke("addToCart", "123", "http://example.com/someReturnUrl");
You may add other parameters if necessary.

Resources