Retrieving state data with oidc-client - oauth-2.0

How to keep the original url that the user was navigating to?
Say I have an unauthenticated user navigates to http://localhost:9000/customer/123
To authenticate the user I would do a:
// in my app.js
new Oidc.UserManager().signinRedirect({state:'customer/123'}); // need a way to keep this url
When that returns to the callback.html where I need a way of going to the origianal url:
// callback.html
<script src="oidc-client.js"></script>
<script>
Oidc.Log.logger = console;
new Oidc.UserManager().signinRedirectCallback().then(function () {
var state = 'customer/123' // how to do a redirect to the page originally requested page?
window.location.href="http://localhost:9000/ + state
}).catch(function (e) {
console.error(e);
});
</script>
Or maybe there are other build in ways of getting the origianl url?
Thanks for any help!

Your approach is good. You sign in the way you are doing it, and then in the callback, slightly modify your code (use the user object that is returned):
new Oidc.UserManager().signinRedirectCallback().then(function (user){
var url = user.state;
//more code here
}
The state will be part of the user object, and will have the value that you have submited. And you can redirect to wherever you want.

Related

.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.

Create a general rule for urls in Laravel

I want to redirect users back to the login page if they attempt to access certain pages on my site. I want to create a general rule so that I do not have to implement it on every page for every url separately.
For example if user try to access /profile , I want them to redirect back to login page if they are not logged in. I tried doing this using group routes by putting an if condition but that did not work. Moreover I am not an expert in laravel. This is what I tried.
Route::group(['prefix' => '/users'], function () {
if(Auth::user()){
Route::get('/','FacebookControllers\FacebookPagesController#listUsers');
Route::get('{id}/profile', 'FacebookControllers\FacebookPagesController#userProfile');
}
else {
return redirect('/');
}
});
Check out laravel's Auth middleware.
Documentation here: laravel.com/docs/5.1/routing#route-groups
Example (taken from the docs):
Route::group(['middleware' => 'auth'], function () {
Route::get('/', function () {
// Uses Auth Middleware
});
Route::get('user/profile', function () {
// Uses Auth Middleware
});
});

How to autosubmit form before an actionlink invokes?

I have an ActionLink:
#Html.ActionLink("Edit","Edit","Item",new{Id=ItemId),null}
There is a form at the top of the page which I need to save when the user clicks on this link and before the "Edit" action invokes.
So something to achieve this when the user clicks on the link may look like:
Save MasterForm
Carry on through to "Edit" Action on "Item" controller with "Id" parameter.
My instinct tells me that I may be looking for some JS??? Not sure.
Any help hugely appreciated.
The way to do this would be:
Add a click listener to the action link
Submit the form using Ajax
Follow the link manually by setting window.location
It would probably be a good idea to display some kind of spinner or popup while the form is submitting, so that the user knows something is happening.
For step 1, you need to select the <a> tags, so I suggest adding a class:
#Html.ActionLink("Edit","Edit","Item",new{Id=ItemId),new{#class="edit-link"}}
Then add some Javascript to intercept the click:
$(document).on("click", ".edit-link", function(e) {
// stop the browser from following the link
e.preventDefault();
var linkUrl = $(this).attr("href");
// submit the form via an Ajax post (assuming the form has "id=MasterForm")
var form = $("#MasterForm");
$.post(form.attr("action"), form.serialize(), function() {
// when complete, navigate to the original link
window.location = linkUrl;
});
});
Try this
#Html.ActionLink("Edit","Edit","Item",new{Id=ItemId),new {#id='btn-link'}}
In JS
$(document).ready(function(){
$('#btn-link').click(function(e){
saveMasterFormDetails();
});
});
function saveMasterFormDetails(){
var masterForm=$('#masterForm');
$.post(url,masterForm.serialize(), function(data){
});
}

Conditional initial page in jquery mobile

I'm using jQuery mobile with PhoneGap, and would like to show a login page the first time the app is used, and show the index page on subsequent loads.
My current solution is to use the following on deviceready
if(!localStorage.registered){
$.mobile.changePage( "#login", { transition: "none"} );
}
However, my issue with this is that you still see the page transition. I would like the login page to be the first page that is visible.
Any advice? Thanks!
This Q is a few months old, it remains unanswered, I don't have any experience with phone gap but I do jQM, so I figured this may help.
I current employ a solution to this on my app by delaying auto initialisation of jQM.
This is an example of how you could based loosely on how my application does it.
(function() {
#stop jQM from auto initialising
$(document).on("mobileinit",function() {
$.mobile.autoInitializePage = false;
});
var my_app = new MyApp();
# custom afterinit event is triggered on the app instance
$(my_app).on('afterinit',function() {
var initial = 'login';
if(localStorage.registered) {
initial = 'home';
}
# set the page hash to our start page
window.location.hash = initial;
#initialise jQM
$.mobile.initializePage();
});
})();
Make sure you secure the thing that decides if login is allowed, in my application I have a data structure that is required by the app ajax in to MyApp.appdata it will only be there if login was actually successful.
Another solution may be to have a proxy page.
A different approach that I employed on another app.
An initial "loading" step, which is just a dummy page.
Make a page in your doc as the first page, eg.
<div id="loading" data-role="page">Loading</div>
in the mobileinit step bind to the pageshow event.
$(document).on("mobileinit",function() {
$('#loading').on('pageshow',function() {
# ...
# do login check here
# ...
var initial = 'login';
if(localStorage.registered) {
initial = 'home';
}
# change to our initial page
$.mobile.changePage(initial);
});
});
What about hiding #registration and #login then do:
if(localStorage.registered){
$('#login').show();
} else {
$('#registration').show();
}

ASP.NET MVC multiple forms, staying on same page

I have forms located in multiple areas in my layout page (not nested).
I have a partial view which performs a post to controller action.
What action result do I return in that post to keep the user on the current page?
Is jquery/ajax my only option? I would rather a solution that didn't depend on javascript, maybe even a solution that degrades nicely.
You can use the Request.Referrer property to see what page the user has come from and then just use that to redirect them back there.
This does introduce other issues, e.g. losing ModelState, so you'll have to design for that. Also note that some users can block sending referrer information in their requests to the server - so the Referrer property can be null.
I would recommend using AJAX and then falling back on this.
You just need to do a RedirectToAction("") back to your main view.
To post a form without submitting the whole page, which refreshes the browser, you need to use Ajax/jQuery. The degraded solution is to submit the whole page like you would with a normal form.
Here's how I do it with jQuery.
Html:
<div id="RequestButtonDiv">
<button id="RequestButton" name="Request" type="button">Request</button>
</div>
This calls AddToCart on my Request controller when the RequestButton button is clicked. The response is placed inside the RequestButtonDiv element.
<script type="text/javascript">
$(document).ready(function () {
$('#RequestButton').click(function (event) {
$('#RequestButton').text('Processing...');
$('#RequestButton').attr('disabled', true);
submitRequest();
});
});
function submitRequest() {
$.ajax({
url: '<%: Url.Action("AddToCart", "Request", new { id = Model.RowId, randomId = new Random().Next(1, 999999) } ) %>',
success: function (response) {
// update status element
$('#RequestButtonDiv').html(response);
}
});
}
</script>
Controller action:
public ActionResult AddToCart(int id)
{
var user = AccountController.GetUserFromSession();
user.RequestCart.AddAsset(id);
return View("~/Views/Assets/Details_AddToCart.ascx");
}
The controller returns a partial view. You could also return Content("some stuff") instead.
Holler if you have questions or need more detail.

Resources