I'm building an app where I have a server that works on REST API and returns me list of users.
I build an backbone module where I render the list of user I get from the server and display it on a page. I question the server about the users according to date, for example -
http://localhost/getUsers/20021989/20021990 - So I get only the users that were born between those dates.
I added the backbone router that each time that I choose a date it navigates to a function getUsers(start, end):
routes: {
"getUsers/:start/:end": "getUsersPreview",
},
and the function is:
getUsersPreview: function(start, end) {
some code here
}
The event is fired whenever I press the button, but when I copy-paste the URL into other tab (http://localhost/#getUsers/20021989/20021990) - It just redirects to the main page or something.
I'm using also Laravel framework for the server side coding.
When a Router is created, you should call Backbone.history.start() to begin monitoring hashchange events, and dispatching routes. Have you called it?
Related
I have a React (CRA) + Node JS application already deployed locally (using the create-react-app build script), I've implemented Google OAuth signin with passportjs and cookieSession for persistence.
The login works fine but there is a strange bug when I Logout and then try to log in again with google OAuth, it just redirects me to a blank page.
This is how I make the request to my google oauth endpoint:
window.open('https://localhost:3000/auth/google', "_self")
That endpoint then is taken by my API:
app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
Doing some troubleshooting it seemed at first the culprit were the cookies because when I delete the site data before trying to login again... then the login works just fine.
However if I delete the cookies only (through the storage panel -> cookies -> delete all, in firefox) the bug still persists, it only disappears when I delete the site data entirely.
Moreover, The second time I try to login the request don't event reach my server.
What I've alredy tried:
Wrapping my login button inside an anchor tag and setting the anchor's tag href to the endpoint url.
Creating an anchor tag and assigning an href with the endpoint url and then clicking that new element programmatically.
None of this worked, the issue still persists.
Fresh firefox profile: this is even weird, the bug appears the very first time I try to login with google in a newly created profile. Again I have to first click the clear cookies and site data button for it to work.
Incognito mode: The issue persists, again the first time I login it works but the second time it redirects me to a blank page and the request is not even reaching my server.
What could be the problem here?
The issue was the service worker that cames with the creat-react-app template, however I didn't want to disable it completely as I want my app to be a PWA, so the next best thing was to disable the service-worker caching specifically for the page from which the user initiates the Google login (the page where the google button is).
For this I had to install the sw-precache package which allows you to modify the default service-worker that came with the create-react-app template (as you cannot directly modify it).
Then you have to create a config file at the root of your project and add these lines, in this case I call it sw-precache-config.js:
module.exports = {
runtimeCaching: [
{
urlPattern: /<the route to ignore>/,
handler: 'networkOnly'
}
]
};
and then in the build script from your package json:
"build": "react-scripts build && sw-precache --config=sw-precache-config.js"
While developing a self-contained exist-db app I ran into some issues with passing on the user's identity during an ajax call.
I have created a standard page that allows the user to login in with his or her standard exist-db account. (It's more or less based on this https://github.com/eXist-db/existdb-login ).
At some point, the users need to create their own entries and upload files, and this is done with an ajax script (I'm using Kartik's bootstrap uploader, but it's basically a standard ajax upload function):
$('#input-24').fileinput({
uploadUrl: "../modules/uploader.xql",
uploadAsync: true,
fileActionSettings : {
uploadExtraData() {
return {
'FileName': $(this).data('title'),
}
}
},
});
Now, of course, this will fail, since it will appear like a GUEST user is trying to create entries, which is an action that is allowed only for registered users.
Does exist-db allow a way to send in my login credentials at this point without having to resort to the standard HTTP login (which is problematic, since it means creating a cookie to memorize the password, which more or less renders the whole login suing exist's mechanisms useless), or is there any way to use the controller instead of an external script?
Thanks in advance!
I think you can add the user and password into the URI to trigger the Ajax client to do basic with. e.g. http://username:password#your-server/some/uri/modules/uploader.xql
For simple, basic authentication we do the following since the page itself is being served from xQuery.
step 1: we create in the page xQuery a variable containing the session info. This should be fine for you ... the result of your login would be an HTML page:
let $sessinfo := util:base64-encode(concat(request:get-parameter('user', ()), ":", request:get-parameter('pass', ())))
step 2: during the build of the result page in xQuery, we turn that into a javascript variable through a simple script command placed in <head> tag:
<script>
var sessinfo = "{$sessinfo}";
</script>
step 3: in Javascript loaded with the page (we use jQuery), after the page is ready we setup authentication for all AJAX requests:
jQuery.ajaxSetup({
headers: {
"Authorization": "Basic " + sessinfo
}
});
After that, any AJAX request made would send basic authentication header with user and password to other xQueries executed with jQuery.ajax
To have an eXistdb session work with XHR (Ajax requests) you need make sure that
login:set-user('my.login.domain', (), false())
is called in the controller before you forward it to your request handler. Otherwise all request will seem to originate from the 'guest' user.
If you want to use vanilla/native JavaScript requests e.g. fetch you also need to tell it to add the credentials to the request:
fetch(url, { credentials: 'same-origin', method: 'GET' })
By the way, the persistent login used in exidtb-login likely uses a cookie value to pick up the session variables stored on the server (JSESSIONID), but I need to check that.
I have 2 laravel projects, 1 for the front end where i m using html css angularjs. The second for api controllers. I call using http post and get the api controllers functions using angularjs to get content data.
In the front end i have a menu this menu appears differently based on user role, if admin or no.
This is done. My problem is the access for views using the url in the browser.
So I have a query where I get for each user what modules in the menu can he see. Now I'm putting the result in Laravel session.
$menu = DB::select menu by user id ... //Getting menu query based on user if admin or no
session(["menu" => $menu);
return session('menu');
I'm getting the results and the menu is showing good in the website based on the logged user if he s admin or no.
Now, to solve the direct url access issue, I want to use this session and compare the url to this session, if the url exists in the session i will let him access, if no i will redirect him to somewhere.
any idea?
I would strongly suggest looking at the Laravel documentation on Authorization before going too far down a custom implementation:
https://laravel.com/docs/5.1/authorization
Without knowing more about how your front-end and back-end applications interact with each other, it is a little difficult to get into speciifics but i shall do my best.
Each page returned by Laravel has access to a Request object which contains information about the request which returned the page. You can access this Request and its assocaited Route using Laravels helper functions (if you are not passing it to the view already). The getPrefix() method will return the root relative url which you can then use as you see fit. For example:
// Return and store the URL as a string
$url = request()->route()->getPrefix();
// Check your session for the URL/s you want to allow and compare to the stored URL
if (session()->get('URL') == $url) {
// User is allowed access to the page
// Do something ...
} else {
// User is not allowed access to this page
// Redirect back or to a route of your choice
return redirect()->back();
}
I hope this gives you some ideas, good luck!
I have a Rails API backend and a ReactJS frontend. My backend sends custom emails that often have confirmation-like links (like email confirmation)
Should the confirmation links point to my backend directly, or should they rather load the frontend first and then make an API call to the backend?
The two alternatives I'm thinking of are:
1 - The email confirmation link hits directly
backend.example.com/email_confirmations/:confirmation_token, which then redirects to a specific success (error) page frontend.example.com/email_confirmation/success(/failure) on my frontend.
On the backend I would only need a Metal controller with minimum modules to perform redirection to the frontend app, the controller is always responding with redirects). If further actions need to be taken from the frontend, they'll hit a different API Endpoint
2 - The email confirmation links opens up my frontend at
frontend.example.com/email_confirmations/:confirmation_token that triggers an API request to backend.example.com/email_confirmations/:confirmation_token.
Then my (Json:api) backend makes a jsonapi-compliant response with a Rails APIController.
What are you doing in practice?
I decided to opt in for the first scenario but maybe systematically calling/loading the frontend first makes more sense?
How do you wire backend/frontend in those scenarios?
I have currently implemented a very simple (Metal) Controller that would just process the incoming parameters perform redirections only to the frontend. I was hoping to define "url helpers" that would point to my frontend like so:
namespace :email_redirection do
# Controller that gets hit by email confirmation links in scenario #1
resources :confirmations
end
namespace :frontend do
frontend_root = Rails.configuration.frontend_host_with_http_and_port
scope frontend_root do
# Generation of URL Helpers for the frontend app
resources :confirmations, only: [] do
get 'successful'
get 'unsuccessful'
end
end
end
And my confirmation controller would be like
class EmailRedirection::ConfirmationsController
def index
svc = MyConfirmationService.new(token: params[:confirmation_token])
if svc.confirm
redirect_to(
frontend_successful_confirmation_url,
email: svc.confirmable.email
)
else
redirect_to(frontend_unsuccessful_confirmation_url)
end
end
end
I'm getting several error and I believe maybe the url helpers are not useable with different host/port... (or I have to pass them explicitely to each call)
How can I handle that ? And if 1. is a good choice, what would be the redirection codes you'd send on success/failure (since they can only be 3xx) ?
Both solutions involve quite some wiring between the backend/frontend and I'm not sure how to best wire things up.
Note : my models use devise but because devise isn't so great with APIs/etc. I'm using my own ConfirmationService that also handles some side-effects. I don't consider Devise to be relevant here
Creating a rails route to an external URL
Can't get my head around $urlRouterPovider...
basically whenever I go to a link it should load associated view and controller. So that works.
$urlRouterProvider.when("/","/home")
$urlRouterProvider.otherwise("/error")
$stateProvider.state('views', {
url: "/:view",
templateUrl: function(stateParams, formResolver) {
return "views/" + stateParams.view + "/" + stateParams.view + "-view.html";
},
controllerProvider: function($stateParams) {
return "" + $stateParams.view + "Ctrl";
}
});
So whenever user goes to http://localhost:3030/#/foo, it loads "views/foo/foo.html" with controller as "fooCtrl", and goes to home by default, and for all other cases errror.
That is cool. What I need though, whenever user goes to http://localhost:3030/#/auth it would redirect to "/auth" on the server, skipping stateProvider. Currently it sees that as a state and tries to find corresponding view and controller.
If you need to redirect them to the server you need to leave out the #/ part of the URL.
The browser ignores the the #/ portion of the URL, which is how AngularJS is able to allow the page you server from localhost:3030/#/ handle the request. This is essentially still just requesting localhost:3030/
If you are wanting to do a true redirect or navigation to /auth on your server, ignore state for that request - you want your browser to make a straight-up HTTP request pointed directly at your server. Use /auth as the action in your form, or post to /auth from within your controller. When you are done on the server, redirect the user back to your Angular application.
Remember as well that you need to have some mechanism for your AngularJS application to know ehnIn our applications, we have the server set a cookie with a JWT token in it that is then used by the AngularJS application to retrieve the user information. This way the AngularJS application knows how to tell when a the user is really logged in (vs. a user going to a URL that represents a logged-in state).