From 0661b780a7172c5396b60019f7ba90719d12c02e Mon Sep 17 00:00:00 2001 From: Santiago Date: Sun, 31 Mar 2019 16:31:32 -0300 Subject: [PATCH 01/11] Test serer: fixes lost users from the whitelist --- utils/server-test/services/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/server-test/services/auth.js b/utils/server-test/services/auth.js index 40af942c..35ea6aee 100644 --- a/utils/server-test/services/auth.js +++ b/utils/server-test/services/auth.js @@ -34,7 +34,7 @@ module.exports = function(app) { _user.token = token return _user } - return user + return _user }) const newUser = Object.assign({}, user) delete newUser.password From 90d00203f4479912d0352265dc6562ecefb241e9 Mon Sep 17 00:00:00 2001 From: Santiago Date: Sun, 31 Mar 2019 16:41:29 -0300 Subject: [PATCH 02/11] Va-Auth: creates a utils module for auth operations --- src/va-auth/src/utils/index.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/va-auth/src/utils/index.js diff --git a/src/va-auth/src/utils/index.js b/src/va-auth/src/utils/index.js new file mode 100644 index 00000000..9ae1ce9a --- /dev/null +++ b/src/va-auth/src/utils/index.js @@ -0,0 +1,31 @@ +/** + * Auth Utils - A function used to create utilities + * + * @param {Object} store The global Vuex store variable + * + * @return {Object} A set of functions to be used in an Edit form. + */ +export default ({ + store +}) => { + return { + + /** + * checkAuthentication - Indicates whether the user is authenticated or not. + * + * @return {Boolean} + */ + isAuthenticated() { + return store.getters['auth/isAuthenticated'] + }, + + /** + * getUser - Returns the user object from the store + * + * @return {Object} The current logged user object + */ + getUser() { + return store.getters['auth/getUser'] + }, + } +} From 31c113f13b48e4fbf2be16edd4f93a616c419ce6 Mon Sep 17 00:00:00 2001 From: Santiago Date: Sun, 31 Mar 2019 16:47:34 -0300 Subject: [PATCH 03/11] Demo App/Auth-Adapter: generalizes the adapter with user and auth fields + Updates demo app adapter usage with new variables --- demo/App.vue | 8 ++++---- demo/va-auth-adapter/axios.adapter.js | 16 ++++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/demo/App.vue b/demo/App.vue index c221930b..eeb6e683 100644 --- a/demo/App.vue +++ b/demo/App.vue @@ -33,17 +33,17 @@ import EditMagazines from './components/magazines/EditMagazines' import createAxiosAdapter from './va-auth-adapter/axios.adapter' import axios from 'axios' -const authModuleName = 'auth' +const authFields = { username: 'username', password: 'password' } const authUrl = 'http://localhost:8888/api/auth' const client = axios const storageKey = 'token' -const userFields = { username: 'username', password: 'password' } +const userField = 'user' const authProvider = createAxiosAdapter(client, { - authModuleName, + authFields, authUrl, storageKey, - userFields, + userField, }) // Articles Views as Array diff --git a/demo/va-auth-adapter/axios.adapter.js b/demo/va-auth-adapter/axios.adapter.js index c1727931..b9cece18 100644 --- a/demo/va-auth-adapter/axios.adapter.js +++ b/demo/va-auth-adapter/axios.adapter.js @@ -9,12 +9,14 @@ export default (client, options = {}) => { } = AuthActionTypes const { + authFields, authUrl, storageKey, - userFields, + userField, } = Object.assign({ + authFields: { username: 'username', password: 'password' }, storageKey: 'token', - userFields: { username: 'username', password: 'password' }, + userField: 'user', }, options); switch (type) { @@ -22,8 +24,8 @@ export default (client, options = {}) => { return new Promise((resolve, reject) => { const headers = { 'Content-Type': 'application/x-www-form-urlencoded', - [userFields.username]: params.username, - [userFields.password]: params.password + [authFields.username]: params.username, + [authFields.password]: params.password } const method = 'post' const url = authUrl @@ -31,7 +33,7 @@ export default (client, options = {}) => { client({ url, headers, method }) .then(response => { const { data } = response - const { [storageKey]: token, user } = data + const { [storageKey]: token, [userField]: user } = data // something more secure maybe? localStorage.setItem(storageKey, token) client.defaults.headers.common['Authorization'] = token @@ -62,7 +64,9 @@ export default (client, options = {}) => { const method = 'get' client({ url, headers, method }) .then(response => { - resolve(response) + const { data } = response + const { [userField]: user } = data + resolve(user) }) .catch(error => { reject(error) From 6788ab98241fd6219cc280b9e5400cdaa5e11221 Mon Sep 17 00:00:00 2001 From: Santiago Date: Sun, 31 Mar 2019 16:48:47 -0300 Subject: [PATCH 04/11] Route Bindings and Hooks: integrates the modules to apply restrictions to routes --- src/router/route.bindings.js | 38 ++++++++++++++++++++++++++++++++---- src/router/route.hooks.js | 21 ++++++++++---------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/router/route.bindings.js b/src/router/route.bindings.js index 76ca6d16..077617ae 100644 --- a/src/router/route.bindings.js +++ b/src/router/route.bindings.js @@ -2,6 +2,7 @@ import listUtils from '@store/utils/list.utils' import showUtils from '@store/utils/show.utils' import createUtils from '@store/utils/create.utils' import editUtils from '@store/utils/edit.utils' +import createAuthUtils from '@va-auth/utils' import createRouteHooks from './route.hooks' /** @@ -37,6 +38,7 @@ export default ({ const hasCreate = !!create const hasEdit = !!edit const resourcePath = `/${resourceName}` + const authUtils = createAuthUtils({ store }) return { list: ({ wrapper }) => { @@ -67,6 +69,12 @@ export default ({ } else { // list is an Object const { component, isPublic, permissions } = list + const routeHooks = createRouteHooks({ + isPublic, + permissions, + store: authUtils, + userPermissionsField + }) return { path: resourcePath, name, @@ -85,7 +93,8 @@ export default ({ meta: { isPublic, permissions - } + }, + ...routeHooks, } } }, @@ -115,6 +124,12 @@ export default ({ } else { // show is an Object const { component, isPublic, permissions } = show + const routeHooks = createRouteHooks({ + isPublic, + permissions, + store: authUtils, + userPermissionsField + }) return { path: `${resourcePath}/show/:id`, name, @@ -129,7 +144,8 @@ export default ({ meta: { isPublic, permissions - } + }, + ...routeHooks, } } }, @@ -162,6 +178,12 @@ export default ({ } else { // create is an Object const { component, isPublic, permissions } = create + const routeHooks = createRouteHooks({ + isPublic, + permissions, + store: authUtils, + userPermissionsField + }) return { path: `${resourcePath}/create`, name, @@ -176,7 +198,8 @@ export default ({ meta: { isPublic, permissions - } + }, + ...routeHooks } } }, @@ -209,6 +232,12 @@ export default ({ } else { // edit is an Object const { component, isPublic, permissions } = edit + const routeHooks = createRouteHooks({ + isPublic, + permissions, + store: authUtils, + userPermissionsField + }) return { path: `${resourcePath}/edit/:id`, name, @@ -223,7 +252,8 @@ export default ({ meta: { isPublic, permissions - } + }, + ...routeHooks } } } diff --git a/src/router/route.hooks.js b/src/router/route.hooks.js index 241d111f..ff621f45 100644 --- a/src/router/route.hooks.js +++ b/src/router/route.hooks.js @@ -1,17 +1,16 @@ - - /** * Create Route Hooks - A function used to create route hooks * * @param {Boolean} isPublic Indicates whether or not a route needs authentication to be visited * @param {Array} permissions An array of route permissions as Strings + * @param {Object} store A group of store auth actions * @param {String} userPermissionsField The name of the permissions field in a user object - * * @return {type} An object with hook functions */ export default({ isPublic, permissions, + store, userPermissionsField }) => { const requiresAuth = !isPublic @@ -20,9 +19,8 @@ export default({ if (requiresAuth) { // It's a private route - // TODO: Gets token from localStorage or authorise in the backend - const token = localStorage.getItem('jwt') - if (token === null) { + const isAuthenticated = store.isAuthenticated() + if (!isAuthenticated) { // User is not authenticated next({ path: '/login', @@ -30,19 +28,20 @@ export default({ }) } else { // User is authenticated - if (permissions.length > 0) { // Route has permissions restriction - // TODO: Gets user from the store - const user = { userPermissions: [] } - const { userPermissions } = user - const userHasPermissions = permissions.some(permission => userPermissions.indexOf(permission) > -1) + const user = store.getUser() + const { [userPermissionsField]: userPermissions } = user + const userHasPermissions = permissions.some(permission => { + return userPermissions.indexOf(permission) > -1 + }) if (userHasPermissions) { // User is authenticated and has route permissions next() } else { // User is authenticated but does not have route permissions + // TODO: Should redirect to an Anauthorized page - #90 - @sgobotta next({ path: '/' }) From 9f12f29e86e5bfb795e01fb8113d11f5e0359dcc Mon Sep 17 00:00:00 2001 From: Santiago Date: Sun, 31 Mar 2019 17:20:43 -0300 Subject: [PATCH 05/11] Updates RADME.md with the authProvider updates --- README.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f87456f9..3a54129e 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,21 @@ npm i --save vue-admin-js ``` +## Configuration + +### Auth Provider +**You will have to configure a simple adapter to communicate with your REST api.** + +**We currently provide a simple example using an axios client in the demo app. Though we intend to keep developing other kind of adapters for different node backend frameworks, they will live in separate packages.** + +**Anyways, we hope the axios example encourages you to write your own adapter until we release the adapters guide. The @va-auth module uses the vuex store and expects a user to make use of the action types it provides.** + ## Usage -***App.vue*** +***Your App.vue file*** ```vue