PROBLEM: I don't know how to get the current session in a controller.
I have a custom authenticator, custom session, and initializer defined like so:
CUSTOM AUTHENTICATOR in ../app/authenticators/custom.js
var CustomAuthenticator = Base.extend({
authenticate: function(credentials) {
return new Ember.RSVP.Promise(function (resolve, reject){
var loginPromise = Ember.$.post('/api/login', {'email':credentials.identification, 'password':credentials.password} );
loginPromise.then(function (data){
resolve({
token: data.user.api_key,
userData: data.user
});
}, function(error){
reject(error);
});
});
}
});
CUSTOM SESSION in ../app/sessions/custom.js
import Ember from 'ember';
import Session from 'simple-auth/session';
var CustomSession = Session.extend({
after:'simple-auth',
currentUser: function(){
return this.container.lookup('ember_simple_auth:session');
}.property('currentUser')
});
export default CustomSession;
INITIALIZER in ../app/initializers/authentication.js
import CustomAuthenticator from '../authenticators/custom';
import CustomSession from '../sessions/custom';
export default {
name: 'authentication',
before: 'simple-auth',
initialize: function(container) {
container.register('authenticator:custom', CustomAuthenticator);
container.register('session:custom', CustomSession);
}
};
I'm trying to get the token and userData in one of my controllers by using this.get('session') but it's giving me the following:
Class {store: Class, __ember1420041799205: "ember297", __nextSuper: undefined, __ember_meta__: Object, constructor: function…}
and I see the ember_simple_auth:session key and values in the local browser storage {"authenticator":"authenticator:custom","token":"123456789","userData":{"id":"1","email":"something#email.com","api_key":"123456789","expiry_time":"2014-12-31 14:02:56"}}
I basically need to get what's in the local storage. How do I do this?
Ah, I figured out the problem. When first authenticating, the session variable was there but refreshing the page got rid of the session's content because I did not have a restore function in my authenticator.
restore: function(data) {
return new Ember.RSVP.Promise(function (resolve, reject){
console.log('RESTORE');
if(!Ember.isEmpty(data.token)) {
console.log('Found token: ' + data.token);
resolve(data);
} else {
console.log('Token Not Found!');
reject();
}
});
}
Related
This example demonstrates how to use Auth0 with react-admin. It is working as expected.
We are trying to adjust it so it will use the hasura data provider. We've created a new file dataProvider.js that will construct the data-provider:
import buildHasuraProvider from "ra-data-hasura";
import { ApolloClient, InMemoryCache } from "#apollo/client";
export const initDataProvider = async (token) => {
const client = new ApolloClient({
uri: process.env.REACT_APP_GRAPHQL_URI,
headers: {
Authorization: `Bearer ${token}`,
},
cache: new InMemoryCache(),
});
const dataProvider = await buildHasuraProvider({ client });
return dataProvider;
};
However, we are missing the JWT token which is created as part of the Auth0 authentication process. We do not know how to get the token in order to initialize the data provider with it. Does react-admin know how to do it on its own? if not, how do we access the JWT token to do it ourselves manually?
This is the authProvider source-code:
import authConfig from "./authConfig";
import {Auth0Client} from '#auth0/auth0-spa-js';
const auth0 = new Auth0Client({
domain: authConfig.domain,
client_id: authConfig.clientID,
redirect_uri: authConfig.redirectURI,
cacheLocation: 'localstorage',
useRefreshTokens: true
});
export default {
// called when the user attempts to log in
login: (url) => {
if (typeof url === 'undefined') {
return auth0.loginWithRedirect()
}
return auth0.handleRedirectCallback(url.location);
},
// called when the user clicks on the logout button
logout: () => {
return auth0.isAuthenticated().then(function (isAuthenticated) {
if (isAuthenticated) { // need to check for this as react-admin calls logout in case checkAuth failed
return auth0.logout({
redirect_uri: window.location.origin,
federated: true // have to be enabled to invalidate refresh token
});
}
return Promise.resolve()
})
},
// called when the API returns an error
checkError: ({status}) => {
if (status === 401 || status === 403) {
return Promise.reject();
}
return Promise.resolve();
},
// called when the user navigates to a new location, to check for authentication
checkAuth: () => {
return auth0.isAuthenticated().then(function (isAuthenticated) {
if (isAuthenticated) {
return Promise.resolve();
}
return auth0.getTokenSilently()
})
},
// called when the user navigates to a new location, to check for permissions / roles
getPermissions: () => {
return Promise.resolve()
},
};
It is unclear to us if there is a point where we can extract the token from.
getTokenSilently should give you back the token.
You'll have to structure your React app such that you have access to the result of this method before you construct your data provider.
im having this issue where i send a request to the API to retrieve all users, the login function is called(index.vue) when called it tries to go to api/users/all which in this case should return all the users in that collection.
using Postman the API returns the correct results and if i console.log the output in the routeUsers before i send the response back, it outputs all the correct data to the console
when it returns to index.vue, the response status code is 0.
ive had a look online and some things are mentioning about CORS Headers but i dont think thats applicable to me and other things about the response has been cancelled,
can anyone shed some light on this for me and help me try to fix it?!
API main.js
var app = express();
var users = require('./routes/routeUsers');
app.use('/users', users);
module.exports = app;
api/models/users.js
var db = require('../Utilities/db')
module.exports.all = function(cb) {
var collection = db.get().collection('users')
collection.find().toArray(function(err, docs) {
cb(err, docs)
})
}
api/routes/routeUsers.js
var express = require('express')
, router = express.Router()
var user = require('../models/users');
router.get('/all', function(req, res) {
user.all(function(err, users) {
res.send(users);
})
})
Index.vue
export default {
data: function () {
return {
username: '',
password: '',
users: []
}
},
methods: {
login: function() {
Vue.http.get('/api/users/all').then((response) => {
console.log("SUCCESS",response);
this.users = response.body;
console.log(users);
}, function (error) {
console.log("Error", error.status); // handle error
});
}
}
};
The issue was that the inputs were in a form tag. removed Form tag and worked fine.
Im trying to get my json result into my react code
The code looks like the following
_getComments() {
const commentList = "AJAX JSON GOES HERE"
return commentList.map((comment) => {
return (
<Comment
author={comment.author}
body={comment.body}
avatarUrl={comment.avatarUrl}
key={comment.id} />);
});
}
How do i fetch AJAX into this?
First, to fetch the data using AJAX, you have a few options:
The Fetch API, which will work out of the box in some browsers (you can use a polyfill to get it working in other browsers as well). See this answer for an example implementation.
A library for data fetching (which generally work in all modern browsers). Facebook recommends the following:
superagent
reqwest
react-ajax
axios
request
Next, you need to use it somewhere in your React component. Where and how you do this will depend on your specific application and component, but generally I think there's two scenarios to consider:
Fetching initial data (e.g. a list of users).
Fetching data in response to some user interaction (e.g. clicking a
button to add more users).
Fetching initial data should be done in the life-cycle method componentDidMount(). From the React Docs:
var UserGist = React.createClass({
getInitialState: function() {
return {
username: '',
lastGistUrl: ''
};
},
componentDidMount: function() {
this.serverRequest = $.get(this.props.source, function (result) {
var lastGist = result[0];
this.setState({
username: lastGist.owner.login,
lastGistUrl: lastGist.html_url
});
}.bind(this));
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
return (
<div>
{this.state.username}'s last gist is
<a href={this.state.lastGistUrl}>here</a>.
</div>
);
}
});
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
mountNode
);
Here they use jQuery to fetch the data. While that works just fine, it's probably not a good idea to use such a big library (in terms of size) to perform such a small task.
Fetching data in response to e.g. an action can be done like this:
var UserGist = React.createClass({
getInitialState: function() {
return {
users: []
};
},
componentWillUnmount: function() {
this.serverRequest && this.serverRequest.abort();
},
fetchNewUser: function () {
this.serverRequest = $.get(this.props.source, function (result) {
var lastGist = result[0];
var users = this.state.users
users.push(lastGist.owner.login)
this.setState({ users });
}.bind(this));
},
render: function() {
return (
<div>
{this.state.users.map(user => <div>{user}</div>)}
<button onClick={this.fetchNewUser}>Get new user</button>
</div>
);
}
});
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
mountNode
);
Lets take a look on the fetch API : https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
Lets say we want to fetch a simple list into our component.
export default MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
lst: []
};
this.fetchData = this.fetchData.bind(this);
}
fetchData() {
fetch('url')
.then((res) => {
return res.json();
})
.then((res) => {
this.setState({ lst: res });
});
}
}
We are fetching the data from the server, and we get the result from the service, we convert is to json, and then we set the result which will be the array in the state.
You can use jQuery.get or jQuery.ajax in componentDidMount:
import React from 'react';
export default React.createClass({
...
componentDidMount() {
$.get('your/url/here').done((loadedData) => {
this.setState({data: loadedData});
});
...
}
First I'd like to use fetchAPI now install of ajax like zepto's ajax,the render of reactjs is asyn,you can init a state in the constructor,then change the state by the data from the result of fetch.
I have tried doing this.get('session') but it gives me nothing.
I want to save data to my session
I only seem to get the information I need from the authenticator but can't seem to be able to pass it around. (Tried a couple of methods suggested on SO but none seem to be able to work from the autheticator)
import Ember from 'ember';
import Torii from 'ember-simple-auth/authenticators/torii';
const { service } = Ember.inject;
export default Torii.extend({
torii: service('torii'),
authenticate(options) {
return this._super(options).then(function (data) {
console.log(data);
});
}
});
Caller of the autheticator (Is the info I need accessible from here already?)
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service('session'),
actions: {
authenticateSession() {
this.get('session').authenticate('authenticator:torii', 'google-token');
},
invalidateSession() {
this.get('session').invalidate();
}
}
});
Your authenticator's authenticate method does not resolve with anything. Change it to
import Ember from 'ember';
import Torii from 'ember-simple-auth/authenticators/torii';
const { service } = Ember.inject;
export default Torii.extend({
torii: service('torii'),
authenticate(options) {
return this._super(options).then(function (data) {
console.log(data);
return data;
});
}
});
to have all attributes in data available via the session's data.authenticated property, e.g. this.get('session.data.authenticated.token').
Of course in this case you can just remove the overridden authenticate method completely if you don't need the logging.
I am still learning Angular JS and have this controller which is making two ajax requests to the lastfm api using different parameters. I want to know when each request has been finished, so that I can display a loading indicator for both requests. I have researched it and read about promises and the $q service but cant get my head around how to incorporate it into this. Is there a better way to set this up? and how can I know when each request is done. Thanks.
angular.module('lastfm')
.controller('ProfileCtrl', function ($scope, ajaxData, usersSharedInformation, $routeParams) {
var username = $routeParams.user;
//Get Recent tracks
ajaxData.get({
method: 'user.getrecenttracks',
api_key: 'key would go here',
limit: 20,
user: username,
format: 'json'
})
.then(function (response) {
//Check reponse for error message
if (response.data.message) {
$scope.error = response.data.message;
} else {
$scope.songs = response.data.recenttracks.track;
}
});
//Get user info
ajaxData.get({
method: 'user.getInfo',
api_key: 'key would go here',
limit: 20,
user: username,
format: 'json'
})
.then(function (response) {
//Check reponse for error message
if (response.data.message) {
$scope.error = response.data.message;
} else {
$scope.user = response.data.user;
}
});
});
I have this factory which handles all the requests
angular.module('lastfm')
.factory('ajaxData', function ($http, $q) {
return {
get: function (params) {
return $http.get('http://ws.audioscrobbler.com/2.0/', {
params : params
});
}
}
});
Quite easy using $q.all(). $http itself returns a promise and $q.all() won't resolve until an array of promises are resolved
var ajax1=ajaxData.get(....).then(....);
var ajax2=ajaxData.get(....).then(....);
$q.all([ajax1,ajax2]).then(function(){
/* all done, hide loader*/
})