My aurelia application has two roots, an app-login and the app root. When users try to access the application and are not logged in, they are sent to the app-login route, which only has 1 route configured, login.
If an unauthenticated user tries to access the app as though they were logged in, (e.g. localhost:3000/#/needsAuthenticationRoute), I want the user to be taken to the login page, however, upon successfully logging in, have them be redirect to the page they were initially trying to access.
I try to handle the issue as follows:
config.mapUnknownRoutes((instruction) => {
let redirectUrl = 'login';
console.log(instruction);
if(instruction.fragment !== '/') {
let redirect = instruction.fragment;
if(instruction.queryString) {
redirect = redirect + '?' + instruction.queryString;
}
redirectUrl = router.generate('login', {redirect});
}
return {redirect: redirectUrl };
});
So from the app-login route, if they try to access needsAuthenticationRoute, they would be redirected back to the login page with a redirect parameter (the user would be sent to localhost:3000/#/login?redirect=%2FneedsAuthenticationRoute in this case).
However, when the user tries to access a route with a query string (e.g. needsAuthenticationRoute?param=value), I would want the user to be redirected to localhost:3000/#/login?redirect=%2FneedsAuthenticationRoute%3Fparam%3Dvalue. However, the redirect keeps around the query parameter and I am left with a route that looks like
localhost:3000/#/login?redirect=%2FneedsAuthenticationRoute%3Fparam%3Dvalue?param=value.
Does anybody know how to clear query the query params when specifying a redirect instruction? Or have an alternative solution to what I am proposing?
I have recently just implemented the exact functionality you describe (I also have a blog post in draft about this topic too - when I get round to publishing it...)
I have a bunch of routes, some that have query strings, some which don't. If the user isn't logged in i want to redirect them to the login page, then after successful login I want to redirect them to where they were going before.
Also, I wanted to keep the "?returnUrl=" query string out of the url, it works, but just felt a bit messy to me - considering that this is all client side routing, i knew i could store it somewhere and "hide" it/
So firstly, we need to stash the route they were going to before login, this is done in a defined AuthorizeStep Aurelia AuthorizeStep
#inject(MyApi)
class AuthorizeStep implements PipelineStep {
constructor(private api: MyApi) { }
public run(navigationInstruction: NavigationInstruction, next: Next): Promise<any> {
if (navigationInstruction.getAllInstructions().some(i => i.config.settings.roles.indexOf("Client") !== -1)) {
if (!this.api.LoggedIn && navigationInstruction.config.name !== "login") {
this.api.RouteFragment = navigationInstruction.fragment;
return next.cancel(new Redirect("login"));
}
}
return next();
}
}
Finally, the login page needs to be made aware that after logging in, the user might be going somewhere. So after a successful login we check to see if anything has been stashed in the RouteFragment
if (loginResult.Success) {
if (this.api.RouteFragment && this.api.RouteFragment.length > 0) {
// Navigate to where the user was trying to go before Logging In
this.router.navigate(this.api.RouteFragment);
} else {
this.router.navigate("/dashboard");
}
}
Related
I have an application that has two authentications i.e user and admin.
I want to redirect the user to a specific page if they are already login. Like if the user is already logged in then the URL http://example.com/log should take the user to URL http://example.com/dashboard.
Similarly, if an admin is already logged in then, URL http://example.com/admin/login
should redirect them to URL http://example.com/admin/dashboard.
The problem is I can change the handle method to redirect to only one page in RedirectIfAuthenticated page. Any idea on how to check if request is from admin or user in that page.
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/dashboard');
}
return $next($request);
}
if you create 2 guards for authentication like user and admin then simply check by below
if (!Auth::guard('user')->user()) {
return redirect('/dashboard');
}
if (!Auth::guard('admin')->user()) {
return redirect('/admin/dashboard');
}
I'm trying to implement Auth0 with lock (version 10.11.0) inside my Angular2 app. Auth0 works if I list every possible route in Auth0's client's Allowed Callback URLs setting. It seems Auth0 picks up the callback URL from whatever URL the user happens to be on when they decide to login. This is not a scalable approach. How do you solve this?
I've tried entering a redirectUrl value in auth options. This gets me a little further in that the app does redirect to the URL supplied, however, Auth0 lock's authenticated callback never fires so I cannot retrieve authenticated user's profile.
So, I'm stuck. It seems my only course of action is to list every conceivable route in Auth0's client's Allowed Callback URLs setting and pray the guys from marketing do not come up with more routes.
Here's my code:
let options =
{
auth:
{
//redirectUrl: 'http://localhost:4200',
//redirect: true,
responseType: 'token',
params:
{
scope: 'openid user_id name nickname email picture'
}
}
};
this.lock = new Auth0Lock('xxx', 'yyy', options);
this.lock.on("authenticated", (authResult) =>
{
console.log('#### AUTH RESULTS:', authResult);
localStorage.setItem('id_token', authResult.idToken);
this.lock.getProfile(authResult.idToken, (error, profile) =>
{
if (error)
{
return;
}
console.log('#### AUTHENTICATED USER PROFILE:', profile);
});
}
Any ideas on how to make Auth0 work so you do not have to list every possible route a user can be on before deciding to authenticate?
These are a couple general questions to really see different implementations of detecting authentication and authorization using Aurelia. All of this is speaking within the context of a secured back-end service.
Say you are using cookie authentication with the server. How are you acknowledging that cookie in Aurelia to display to the user that they are logged in?
In the Aurelia documentation(seen here), we can see the following:
class AuthorizeStep {
run(navigationInstruction, next) {
if (navigationInstruction.getAllInstructions().some(i =>
i.config.settings.roles.indexOf('admin') !== -1)) {
var isAdmin = /* insert magic here */false;
if (!isAdmin) {
return next.cancel(new Redirect('welcome'));
}
}
return next();
}
}
What does /* insert magic here */ look like for you? What should it look like?
The app I am currently working on requests a token from the server at the 'login' route using XHR. If this request is successful, and a token was received from the backend, then the token is stored in a cookie and we route away from the login page to the main content of the app. We could then set a global variable 'loggedIn' to display that the user is logged in, etc. Each time we make further requests to the backend via XHR, we send the token with the request.
The 'magic' in the authorize step is just some logic that checks to see if the user is logged in, or in the example above, an admin.
I have an ember application that uses the Auth0 Ember Simple Auth addon to use the Ember-Simple-Auth functionality with Auth0's Lock.js. Recently I have been trying to implement single-sign-onfunctionality, such that if a user logs into a login portal application, their session will be preserved for other applications on the same domain, and they will not need to log in repeatedly. However my implementation of SSO is resulting in an infinite redirect loop between my login logic and Auth0's endpoint.
I have enabled SSO in the Auth0 application settings. My login is implemented in a few blocks.
My route.js contains a beforeModel() method which contains:
if (!get(session, 'isAuthenticated')){
// Forward to the login action
}
My login action:
login() {
var session = get(this, 'session');
session.authenticate('authenticator:myauthenticator', { authParams: { scope: 'openid' } });
}
This grabs the session object, and calls my custom authenticator. So far, this is basically just ember-simple-auth boilerplate, and complies with the examples supplied in the Auth0 Ember-Simple-Auth documentation.
Where I run into trouble is my custom authenticator. The base authenticator is here. You can see that it handles basic login logic easily, including showing the Auth0 lock when a user isn't authenticated. However it has no logic for handling the kind of SSO-session checking that I want to implement. So I implemented a custom authenticator as below, using examples provided by Auth0 for (basically) this exact scenario (you can see their examples [here], I'm using a slightly altered version)3:
authenticate(options) {
return new Ember.RSVP.Promise((res) => {
// the callback that will be executed upon authentication
var authCb = (err, profile, jwt, accessToken, state, refreshToken) => {
if (err) {
this.onAuthError(err);
} else {
var sessionData = { profile, jwt, accessToken, refreshToken };
this.afterAuth(sessionData).then(response => res(this._setupFutureEvents(response)));
}
};
var lock = this.get('lock');
// see if there's a SSO session available
lock.$auth0.getSSOData(function(err, data) {
if (!err && data.sso) {
// there is! redirect to Auth0 for SSO
options.authParams.callbackOnLocationHash = true;
lock.$auth0.signin(options.authParams, authCb);
} else {
// regular login
lock.show(options, authCb);
}
});
});
}
This behaves mostly as I would expect it to. When I log in with an existing session from another SSO-enabled app on the same domain, if (!err && data.sso) resolves to true, and lock.$auth0.signin(options.authParams, authCb) is called. However, this signin logic is not working as intended. Auth0.signin calls the Auth0.authorize method, which generates a target URL that looks something like:
https://mydomain.auth0.com/authorize?scope=openid&response_type=token&callbackOnLocationHash=true&sso=true&client_id=(MyClientIdHash)&redirect_uri=localhost%23access_token%3(MyAccessToken)%26id_token%3(MyIdToken1).(MyIdToken2).(MyIdToken3)token_type%3DBearer&auth0Client=(MyAuth0Client)
My application is then redirected to this URL for authorization. I get a 302 and am redirected back to the callback URL (my root page). Because there is a new page transition, if (!get(session, 'isAuthenticated')) is hit again. It returns false, and so the same logic repeats itself, looping indefinitely.
Does anyone have any insight on what I might be doing incorrectly here? The authorize endpoint seems to behave as if I were being authenticated, but then the authentication is never actually triggered. I've debugged through this code fairly extensively but seen no obvious red flags, and I've followed provided examples closely enough that I'm not sure what I would change. I'm not entirely sure where the failure to authenticate is happening such that get(session, 'isAuthenticated') is false.
I am experimenting with Grails 3 Interceptors. Given the following interceptor:
class AuthInterceptor {
AuthInterceptor() {
matchAll().includes(controller:"account")
}
// Intercept anything under /account.
boolean before() {
User user = SimpleSecurityUtils.getCurrentUser()
if(user != SimpleSecurityUtils.anonymous) {
// Only get here if the user is currently authenticated. Redirect them to where they want to go.
true
} else {
redirect(controller: auth, action: signin)
true ??
}
}
boolean after() { true }
void afterView() {
// no-op
}
}
matchAll().includes(...) doesn't actually exist on the Matcher object. So how do I actually say "only intercept requests to the AccountController"?
If you follow the auth logic, if the user is currently anonymous (not logged in), I want to redirect them to the AuthController#signin action, which will present them with a login screen. It doesn't appear that the redirect(...) closure is available to interceptors...so how do I perform this redirect safely? Furthermore, how do I "save off" the URL we are currently intercepting so that, after successful login, the user can yet again be redirected to the originally-requested URL?
I say safely above because I've had issues with Grails CannotRedirectExceptions being thrown if too many redirects keep getting tossed around, and those errors are usually assuaged by returning after performing a redirect per this previous answer.
For #1, match( controller: "account" ) should do the trick. Don't know the answer to #2.