I have 2 application one in struts and other one is in spring. From struts application I have one link which will call spring application controller through ajax call which returns model.
In struts application I have session timeout for 20 mins and while doing any transaction for the spring application which is rendered in the struts application the session timeout in struts application remains same and after 20 mins it is logging out.
struts application jsp page.
<body>
<div id="content"></div>
</body>
<script type="text/javascript">
$(document).ready(function() {
var sessionId = '<%= sessionId %>'
$.ajax({
type: "GET",
url: '/springapp/index.app?id='+sessionId,
data: "" ,
success: function(response){
$('#content').html(response);
},
error: function(e){
alert('Error: ' + e);
console.log(e)
}
});
});
</script>
Spring application controller.
#RequestMapping(value = "/*.app", method = {RequestMethod.GET, RequestMethod.POST})
public String jspController(ServletRequest req, ServletResponse res) throws exception {
LOGGER.debug("inside jspController() start");
HttpServletRequest request = (HttpServletRequest) req;
String model = request.getRequestURI();
if (model.endsWith("index.app")) {
String sessionKey = request.getParameter("employeeId");
SpringStrutsHandshake springStrutsHandshake = securityDelegate.getUserId(sessionKey);
User user = userDelegate.getUserByEmployeeId(springStrutsHandshake.getUserId());
user.setSessionKey(sessionKey);
request.setAttribute("USER", user);
model = "candidateList";
} else {
model = model.substring(model.lastIndexOf("/") + 1, model.lastIndexOf("."));
}
return model;
}
could you please help me how to fix timeout issue when there is any transaction in the rendered spring applicaiton page?
If you don't want the session timeout in struts application, why don't you just keep sending requests periodically(maybe every 15 mins) to the struts app which does nothing but just to keep the session from idling, until spring app calls back.
Or you can add a method to dynamically set the session timeout time like this
request.getSession.setMaxInactiveInterval(60*60); //in seconds
Related
I am doing a simple new view on a MVC ASP .NET
Here, I am doing the href:
$(document).on('click', '.viewFormacion', function () {
var id = $(this).data("id");
location.href = baseURL + "Farmacia/ModalPopUp/";
});
Farmacia is the controller and ModalPopUp is the method.
Inside FarmaciaController I have the method:
public ActionResult ModalPopUp(int id, int vid = 0)
{
return View();
}
I created also a new simple View Called ModalPopUp.
When I am going to Farmacia/ModalPopUp/ I received the error.
You don't have authorization to view this page.
HTTP ERROR 403
Can anyone help me?
In my Symfony 3 app I made so, that if the user is inactive for some time, it is logged out and requested to login again. This is done with the following code:
//RequestListener.php
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST != $event->getRequestType()) {
return;
}
if ($this->maxIdleTime > 0) {
$lapse = time() - $this->session->getMetadataBag()->getCreated();
$lapse_short = time() - $this->session->getMetadataBag()->getLastUsed();
if ($lapse >= $this->maxIdleTime || $lapse_short >= $this->shortIdleTime) {
$username = $this->securityToken->getToken()->getUser();
if ($username !== 'anon.'){
$this->session->invalidate();
$this->securityToken->setToken(null);
$event->setResponse(new RedirectResponse($this->router->generate('login')));
}
}
}
}
But in ths case redirect to login form is happened when the page is reloaded. I also want to force redirect on every ajax call also. By default my ajax calls are served by the following address: /ajax
But when the session is expired the ajax is 'redirected' to my login page address and in browsers Network tab I see the following:
My ajax function which is supposed to redirect is as follows:
function requestAjax(json_data, url) {
if(url.indexOf('login') !== -1){
window.location = './login';
}
var request = $.ajax({
url: root + '/' + url
, method: 'post'
, data: json_data
});
return request;
}
But no redirect is happened. So The question is how to force redirect on expired sessions and ajax calls and also why ajax status is 200 but not say 302 in this case? Thank you
UPD_1 My services.yml for RequestListener.php
app.handler.session_idle:
class: AppBundle\EventListener\RequestListener
arguments: ["#session", "#security.token_storage", "#router", "#app.logger", "%session_lifetime%", "%session_active_lifetime%", "%instance_path%"]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
You could try something like this (tested and working in Symfony 2.8)
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
class AjaxAuthenticationListener {
/*
* function onCoreException
* Check if session is expired and handles security related exceptions
* #param GetResponseForExceptionEvent $event An GetResponseForExceptionEvent instance
*
*/
public function onCoreException(GetResponseForExceptionEvent $event) {
$exception = $event->getException();
$event_request = $event->getRequest();
$session = $event->getRequest()->getSession();
if ($event_request->isXmlHttpRequest()) {
if ($exception instanceof AuthenticationException || $exception instanceof AccessDeniedException) {
$session->getFlashBag()->add('warning', 'You have been signed out automatically due to inactivity.');
$event->setResponse(new Response('Session expired', 403));
}
}
}
}
As you can see, "onCoreException" function returns a 403 status code.
Now, in home page (in my case) or page where you will have ajax calls, you could use "ajaxError" and catch the jqXHR.status, if it is 403, then redirect to login page and using a "FlashBag" to display a message related to expired session.
$(document).ready(function () {
//Catch AjaxAuthenticationListener response
$(document).ajaxError(function (event, jqXHR) {
if (403 === jqXHR.status) {
$(location).attr('href', '{{ path('login') }}');
}
});
I have omitted explain how "onCoreException" function works as a service and how it handles the session when it has been expired, taking into account that this part is working properly in your code.
services.yml:
app.gt.ajax.authentication.listener:
class: AppBundle\EventListener\AjaxAuthenticationListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onCoreException, priority: 1000 }
I hope this is useful for you.
Symfony 5 solution
Have been researching on this care for quite some hours. In the symfony 5 How to Customize Access Denied Responses docs, you can customize one of the following:
1. App entry point
2. Access denied handler
3. All Access Denied Responses
Going with customizing All Access Denied Responses, i created a kernel.exception subscriber/listener:
namespace App\EventSubscribers;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class AccessDeniedHandler implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
// the priority must be greater than the Security HTTP
// ExceptionListener, to make sure it's called before
// the default exception listener
KernelEvents::EXCEPTION => ['onKernelException', 2]
];
}
public function onKernelException(ExceptionEvent $event): void
{
// Ajax is returning login page instead of session expired/access denied
// Creating a custom handler for ajax
// more at https://symfony.com/doc/current/security/access_denied_handler.html#customize-the-unauthorized-response
$request = $event->getRequest();
if($request->isXmlHttpRequest()){
$event->setResponse(new Response('Your session has expired!', 403));
return;
}
}
}
It's about time I call in the big guns for this as I can't seem to figure it out.
I have a simple CRUD API in Node. I'm using EJS on the front-end. Essentially, I've got a selectAllRecords view where I display a table of all the records. I have a button next to each record to edit the record. When the button is clicked, it redirects to an editrecord.ejs page, hits the API for a single record where each line is displayed as a value in an input box. From there, I have an onclick method with an XMLHttpRequest making a put request to update the database. However, I'm getting an error - 500 (Internal Server Error) - I'm sure it's something fairly simple I'm missing, but I can't seem to figure it out.
Any help is greatly appreciated! Code below:
First on my view:
<script type="text/javascript">
function someFunc() {
var id = <%= id %>;
var url = '/api/edit/' + candID;
console.log('url ' + url);
var name = document.getElementById("name").value;
var email = document.getElementById("email").value;
var data = {
name: name,
email: email,
}
var json = JSON.stringify(data);
console.log('json ' + json);
var xhr = new XMLHttpRequest();
xhr.open("PUT", url, true);
xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
xhr.send(json);
};
and in my queries.js file:
function updateCandidate(req, res, next) {
var candID = parseInt(req.params.id);
console.log('hit update');
console.log('name ' + req.body.name);
db.none('update cands set name=$1, email=$2 where id=$3',
[req.body.name, req.body.email, candID])
.then(function () {
var candID = candID
var name = data.name;
var email = data.email;
res.render("edited", {"candID":candID, "name":name, "email":email});
})
.catch(function (err) {
return next(err);
});
}
A potentially important note, when I hit the update button and execute the someFunc() function, the dev tool logs show a PUT request to 'api/edit/50' (or whatever ID) and '500 (Internal Server Error)' -- If i hard reload the 'getAllRecords' view, the updates are reflected so it's an issue with the render or redirect (I've tried both)
EDIT
As suggested, I removed the render from the updateCandidate method, but I still get a 500 Internal Server Error. the devtools show me the PUT request is hitting the right URL so i'm really not sure why this isn't functioning correctly. Updated code below...
function updateCandidate(req, res, next) {
var candID = parseInt(req.params.id);
db.none('update cands set name=$1, email=$2, client=$3, jobtitle=$4, question1=$5, question2=$6, question3=$7 where id=$8',
[req.body.name, req.body.email, req.body.client,
req.body.jobtitle, req.body.question1, req.body.question2, req.body.question3, candID])
.then(function (data, err) {
res.status(200)
.json({
status: 'success',
message: `Edited Candidate`
});
})
.catch(function (err) {
return next(err);
});
}
You are sending an ajax request to update the record. So, you should not try to render a view or redirect user as the response of this request. Instead, you can send back a JSON object with some properties e.g. "status".
Then on client side, you check the returned JSON response and based on "status" parameter ( or any other you chose ), you can either update your data or reload the page using window.reload on client side.
Your db query says
db.none('update cands set name=$1, email=$2 where id=$8', [req.body.name, req.body.email]) ...
Shouldn't it be
db.none('update cands set name=$1, email=$2 where id=$8', [req.body.name, req.body.email, candID])
I have searched quite a lot regarding my problem and I couldn't find any relevant tutorial. Moreover, I am not even sure if it is possible using client side technology.
Problem statement: For e.g I have many pages in my web app and if a user switch from index page to page 1 and then page 2. Now the user decides to login to my web site. I want to redirect the user to page 2 once the login is successful.
Current outcome: Once the login is successful user always seems to get redirected to the index page.
Desired outcome: Once the login is successful the user should stay on page 2.
Is it possible using client side technology? In PHP we could use sessions and all. But I am confined on using client side technology to achieve that.
Here is my login function
function login(params) {
if(checkEmpty("loginEmail") && checkEmpty("password")) {
var emailField = $("#loginEmail").val(),
passwordField = $("#password").val(),
data = "login=" + emailField + "&password=" + passwordField;
for (var key in params) {
data += "&" + key + "=" + params[key];
}
// Hide errors as default
$("#loginErrorWrapper").hide();
// Try to launch the "normal" submit operation to make browser save email-field's value to cache
$('#loginSubmitHidden').click();
// Send data to server and refresh the page if everything is ok
$.when(loginPost(data)).done(function(map) {
if(!hasErrors(map)) {
var lang = map.language;
if (lang != "") {
changeLanguage(lang)
}
else {
lang = 'en';
}
redirect("/" + lang + "/");
} else {
if (map.errorCode == "155") {
$.fancybox({
href : '#termsAcceptancePopup',
title : '',
beforeLoad : function() {
$('#acceptTermsButton').attr('onclick','javascript:login({policyChecked:true});$.fancybox.close();');
},
helpers : {
overlay : { closeClick: false }
}
});
} else {
var errorString = getErrorMessage(map);
$("#loginErrorWrapper").show();
$("#loginErrorWrapper").html(errorString);
}
}
});
}
}
Ajax request
function loginPost(data) {
return $.ajax({
url: "/some-api/login",
type: "POST",
dataType: "json",
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
async: true,
data:data
});
}
P.S -> I am not using PHP at all. I am working on a Java based web app.
So I have tried all the methods suggested in the comment section and all of them worked.
1) Using location.reload()
Once the user is logged in it just refresh the page.
2) Saving the last URL in a cookie
Calling the below function before calling redirect.
createCookie(value1, value2, value3);
function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
3) Removing redirect("/" + lang + "/"); from my function since I am using ajax for login. However this method is not useful because once the user is logged in he/she will never know whether everything went fine or not unless he/she refresh the page manually or go to another page.
I am not certain which method is better (performance and loading time) - method 1 or method 2.
I have an Ajax form that I need to hit a JavaScript function on failure, like so:
using (Ajax.BeginForm("UpdateStages", new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "refreshSearchResults('" + #Model.First().ItemCode + "')",
OnFailure = "showError"
}))
With the showError function taking the Ajax context response and appending it to a div, like so:
function showError(ajaxContext)
{
var response = ajaxContext.responseText;
response = $($.trim(response));
var itemVersion = response.filter("div")[0].innerHTML.trim().toString();
var error = response.filter("p")[0].outerHTML.toString();
$("#" + itemVersion.replace(".", "") + "-UpdateStagesResults").empty();
$(error).appendTo("#" + itemVersion.replace(".", "") + "-UpdateStagesResults");
}
In order for the OnFailure to be called I have in my MVC controller ActionResult, when an error occurs:
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return PartialView();
which returns a PartialView with the error message in the ViewBag. This works fine when running locally, the error message is sent to the showError function and then the error is appended to the page.
The problem is that when I put the application onto a live server (IIS7), the Ajax context is just
Bad Request
and for example is not:
<p>You have not entered a valid date.</p>
<div style="display:none;">V7.0 </div>
Any help would be great!
I've had this,
in IIS7 the default error settings are to show detailed error messages locally only., your view is replaced with the default for the status code.
If you want to see your custom errors, add this into your web.config
<system.webServer>
<httpErrors errorMode="Detailed" />
</system.webServer>
that should sort it