Add support for direct authenticated URL access
This commit is contained in:
parent
f132970535
commit
9c9bb16cf2
|
@ -39,6 +39,8 @@ export default defineComponent({
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
// Overall app styles
|
// Overall app styles
|
||||||
|
html
|
||||||
|
scroll-behavior: smooth
|
||||||
h3
|
h3
|
||||||
font-size: 1.75rem
|
font-size: 1.75rem
|
||||||
h4
|
h4
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<router-link to="/"><v-icon icon="mdi-home" /> Home</router-link>
|
<router-link to="/"><v-icon icon="mdi-home" /> Home</router-link>
|
||||||
<router-link to="/profile/seeking"><v-icon icon="mdi-view-list-outline" /> Job Seekers</router-link>
|
<router-link to="/profile/seeking"><v-icon icon="mdi-view-list-outline" /> Job Seekers</router-link>
|
||||||
<a :href="authUrl"><v-icon icon="mdi-login-variant" /> Log On</a>
|
<router-link to="/citizen/log-on"><v-icon icon="mdi-login-variant" /> Log On</router-link>
|
||||||
</template>
|
</template>
|
||||||
<router-link to="/how-it-works"><v-icon icon="mdi-help-circle-outline" /> How It Works</router-link>
|
<router-link to="/how-it-works"><v-icon icon="mdi-help-circle-outline" /> How It Works</router-link>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -30,18 +30,6 @@ export default defineComponent({
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/** The authorization URL to which the user should be directed */
|
|
||||||
authUrl: (() => {
|
|
||||||
/** The client ID for Jobs, Jobs, Jobs at No Agenda Social */
|
|
||||||
const id = 'k_06zlMy0N451meL4AqlwMQzs5PYr6g3d2Q_dCT-OjU'
|
|
||||||
const client = `client_id=${id}`
|
|
||||||
const scope = 'scope=read:accounts'
|
|
||||||
const redirect = `redirect_uri=${document.location.origin}/citizen/authorized`
|
|
||||||
const respType = 'response_type=code'
|
|
||||||
// TODO: move NAS base URL to config
|
|
||||||
return `https://noagendasocial.com/oauth/authorize?${client}&${scope}&${redirect}&${respType}`
|
|
||||||
})(),
|
|
||||||
|
|
||||||
/** Whether a user is logged in or not */
|
/** Whether a user is logged in or not */
|
||||||
isLoggedOn: computed(() => store.state.user !== undefined)
|
isLoggedOn: computed(() => store.state.user !== undefined)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,72 +1,130 @@
|
||||||
import { createRouter, createWebHistory, RouteLocationNormalized, RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
|
import {
|
||||||
import Home from '../views/Home.vue'
|
createRouter,
|
||||||
|
createWebHistory,
|
||||||
|
RouteLocationNormalized,
|
||||||
|
RouteLocationNormalizedLoaded,
|
||||||
|
RouteRecordName,
|
||||||
|
RouteRecordRaw
|
||||||
|
} from 'vue-router'
|
||||||
|
import store from '@/store'
|
||||||
|
import Home from '@/views/Home.vue'
|
||||||
|
import LogOn from '@/views/citizen/LogOn.vue'
|
||||||
|
|
||||||
|
/** The URL to which the user should be pointed once they have authorized with NAS */
|
||||||
|
export const AFTER_LOG_ON_URL = 'jjj-after-log-on-url'
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw> = [
|
const routes: Array<RouteRecordRaw> = [
|
||||||
{ path: '/', component: Home },
|
{
|
||||||
{ path: '/how-it-works', component: () => import(/* webpackChunkName: "help" */ '../views/HowItWorks.vue') },
|
path: '/',
|
||||||
{ path: '/privacy-policy', component: () => import(/* webpackChunkName: "legal" */ '../views/PrivacyPolicy.vue') },
|
name: 'Home',
|
||||||
{ path: '/terms-of-service', component: () => import(/* webpackChunkName: "legal" */ '../views/TermsOfService.vue') },
|
component: Home
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/how-it-works',
|
||||||
|
name: 'HowItWorks',
|
||||||
|
component: () => import(/* webpackChunkName: "help" */ '../views/HowItWorks.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/privacy-policy',
|
||||||
|
name: 'PrivacyPolicy',
|
||||||
|
component: () => import(/* webpackChunkName: "legal" */ '../views/PrivacyPolicy.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/terms-of-service',
|
||||||
|
name: 'TermsOfService',
|
||||||
|
component: () => import(/* webpackChunkName: "legal" */ '../views/TermsOfService.vue')
|
||||||
|
},
|
||||||
// Citizen URLs
|
// Citizen URLs
|
||||||
|
{
|
||||||
|
path: '/citizen/log-on',
|
||||||
|
name: 'LogOn',
|
||||||
|
component: LogOn
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/citizen/authorized',
|
path: '/citizen/authorized',
|
||||||
|
name: 'CitizenAuthorized',
|
||||||
component: () => import(/* webpackChunkName: "dashboard" */ '../views/citizen/Authorized.vue')
|
component: () => import(/* webpackChunkName: "dashboard" */ '../views/citizen/Authorized.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/citizen/dashboard',
|
path: '/citizen/dashboard',
|
||||||
|
name: 'Dashboard',
|
||||||
component: () => import(/* webpackChunkName: "dashboard" */ '../views/citizen/Dashboard.vue')
|
component: () => import(/* webpackChunkName: "dashboard" */ '../views/citizen/Dashboard.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/citizen/profile',
|
path: '/citizen/profile',
|
||||||
|
name: 'EditProfile',
|
||||||
component: () => import(/* webpackChunkName: "profedit" */ '../views/citizen/EditProfile.vue')
|
component: () => import(/* webpackChunkName: "profedit" */ '../views/citizen/EditProfile.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/citizen/log-off',
|
path: '/citizen/log-off',
|
||||||
|
name: 'LogOff',
|
||||||
component: () => import(/* webpackChunkName: "logoff" */ '../views/citizen/LogOff.vue')
|
component: () => import(/* webpackChunkName: "logoff" */ '../views/citizen/LogOff.vue')
|
||||||
},
|
},
|
||||||
// Profile URLs
|
// Profile URLs
|
||||||
{
|
{
|
||||||
path: '/profile/view/:id',
|
path: '/profile/view/:id',
|
||||||
|
name: 'ViewProfile',
|
||||||
component: () => import(/* webpackChunkName: "profview" */ '../views/profile/ProfileView.vue')
|
component: () => import(/* webpackChunkName: "profview" */ '../views/profile/ProfileView.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/profile/search',
|
path: '/profile/search',
|
||||||
|
name: 'SearchProfiles',
|
||||||
component: () => import(/* webpackChunkName: "profview" */ '../views/profile/ProfileSearch.vue')
|
component: () => import(/* webpackChunkName: "profview" */ '../views/profile/ProfileSearch.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/profile/seeking',
|
path: '/profile/seeking',
|
||||||
|
name: 'PublicSearchProfiles',
|
||||||
component: () => import(/* webpackChunkName: "seeking" */ '../views/profile/Seeking.vue')
|
component: () => import(/* webpackChunkName: "seeking" */ '../views/profile/Seeking.vue')
|
||||||
},
|
},
|
||||||
// "So Long" URLs
|
// "So Long" URLs
|
||||||
{
|
{
|
||||||
path: '/so-long/options',
|
path: '/so-long/options',
|
||||||
|
name: 'DeletionOptions',
|
||||||
component: () => import(/* webpackChunkName: "so-long" */ '../views/so-long/DeletionOptions.vue')
|
component: () => import(/* webpackChunkName: "so-long" */ '../views/so-long/DeletionOptions.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/so-long/success',
|
path: '/so-long/success',
|
||||||
|
name: 'DeletionSuccess',
|
||||||
component: () => import(/* webpackChunkName: "so-long" */ '../views/so-long/DeletionSuccess.vue')
|
component: () => import(/* webpackChunkName: "so-long" */ '../views/so-long/DeletionSuccess.vue')
|
||||||
},
|
},
|
||||||
// Success Story URLs
|
// Success Story URLs
|
||||||
{
|
{
|
||||||
path: '/success-story/list',
|
path: '/success-story/list',
|
||||||
|
name: 'ListStories',
|
||||||
component: () => import(/* webpackChunkName: "success" */ '../views/success-story/StoryList.vue')
|
component: () => import(/* webpackChunkName: "success" */ '../views/success-story/StoryList.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/success-story/add',
|
path: '/success-story/add',
|
||||||
|
name: 'AddStory',
|
||||||
component: () => import(/* webpackChunkName: "succedit" */ '../views/success-story/StoryAdd.vue')
|
component: () => import(/* webpackChunkName: "succedit" */ '../views/success-story/StoryAdd.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/success-story/view/:id',
|
path: '/success-story/view/:id',
|
||||||
|
name: 'ViewStory',
|
||||||
component: () => import(/* webpackChunkName: "success" */ '../views/success-story/StoryView.vue')
|
component: () => import(/* webpackChunkName: "success" */ '../views/success-story/StoryView.vue')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
/** The routes that do not require logins */
|
||||||
|
const publicRoutes : Array<RouteRecordName> = [
|
||||||
|
'Home', 'HowItWorks', 'PrivacyPolicy', 'TermsOfService', 'LogOn', 'CitizenAuthorized', 'PublicSearchProfiles',
|
||||||
|
'DeletionSuccess'
|
||||||
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(process.env.BASE_URL),
|
history: createWebHistory(process.env.BASE_URL),
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
scrollBehavior (to: RouteLocationNormalized, from: RouteLocationNormalizedLoaded, savedPosition: any) {
|
scrollBehavior (to : RouteLocationNormalized, from : RouteLocationNormalizedLoaded, savedPosition : any) {
|
||||||
return savedPosition ?? { top: 0, left: 0 }
|
return savedPosition ?? { top: 0, left: 0 }
|
||||||
},
|
},
|
||||||
routes
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
router.beforeEach((to : RouteLocationNormalized, from : RouteLocationNormalized) =>{
|
||||||
|
if (store.state.user === undefined && !publicRoutes.includes(to.name || '')) {
|
||||||
|
window.localStorage.setItem(AFTER_LOG_ON_URL, to.fullPath)
|
||||||
|
return '/citizen/log-on'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
import { computed, defineComponent, onMounted } from 'vue'
|
import { computed, defineComponent, onMounted } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useStore } from '@/store'
|
import { useStore } from '@/store'
|
||||||
|
import { AFTER_LOG_ON_URL } from '@/router'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Authorized',
|
name: 'Authorized',
|
||||||
|
@ -21,7 +22,15 @@ export default defineComponent({
|
||||||
const code = router.currentRoute.value.query.code
|
const code = router.currentRoute.value.query.code
|
||||||
if (code) {
|
if (code) {
|
||||||
await store.dispatch('logOn', code)
|
await store.dispatch('logOn', code)
|
||||||
if (store.state.user !== undefined) { router.push('/citizen/dashboard') }
|
if (store.state.user !== undefined) {
|
||||||
|
const afterLogOnUrl = window.localStorage.getItem(AFTER_LOG_ON_URL)
|
||||||
|
if (afterLogOnUrl) {
|
||||||
|
window.localStorage.removeItem(AFTER_LOG_ON_URL)
|
||||||
|
router.push(afterLogOnUrl)
|
||||||
|
} else {
|
||||||
|
router.push('/citizen/dashboard')
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
store.commit('setLogOnState', 'Did not receive a token from No Agenda Social (perhaps you clicked "Cancel"?)')
|
store.commit('setLogOnState', 'Did not receive a token from No Agenda Social (perhaps you clicked "Cancel"?)')
|
||||||
}
|
}
|
||||||
|
|
30
src/JobsJobsJobs/App/src/views/citizen/LogOn.vue
Normal file
30
src/JobsJobsJobs/App/src/views/citizen/LogOn.vue
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<template>
|
||||||
|
<p><em>Sending you over to No Agenda Social to log on; see you back in just a second…</em></p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component simply redirects the user to the No Agenda Social authorization page; it is separate here so that it
|
||||||
|
* can be called from two different places, and allow the app to support direct links to authorized content.
|
||||||
|
*/
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'LogOn',
|
||||||
|
setup () {
|
||||||
|
/** The authorization URL to which the user should be directed */
|
||||||
|
const authUrl = (() => {
|
||||||
|
/** The client ID for Jobs, Jobs, Jobs at No Agenda Social */
|
||||||
|
const id = 'k_06zlMy0N451meL4AqlwMQzs5PYr6g3d2Q_dCT-OjU'
|
||||||
|
const client = `client_id=${id}`
|
||||||
|
const scope = 'scope=read:accounts'
|
||||||
|
const redirect = `redirect_uri=${document.location.origin}/citizen/authorized`
|
||||||
|
const respType = 'response_type=code'
|
||||||
|
return `https://noagendasocial.com/oauth/authorize?${client}&${scope}&${redirect}&${respType}`
|
||||||
|
})()
|
||||||
|
document.location.assign(authUrl)
|
||||||
|
|
||||||
|
return { }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
Loading…
Reference in New Issue
Block a user