how to add authentication in nuxt.js content docs theme - javascript

I have created a NUXT.JS content static site served with .md files. Now i want to add authentication to it. I want to redirect a user form my main site which is built in VUE.JS
User have to login to my main site and then clicking on a link -> redirect the user to nuxt site
Here are my nuxt configs:
import theme from '#nuxt/content-theme-docs'
export default theme({
docs: {
primaryColor: '#E24F55'
},
content: {
liveEdit: false
},
buildModules: [
'#nuxtjs/color-mode'
],
colorMode: {
preference: '', // default value of $colorMode.preference
fallback: 'light', // fallback value if not system preference found
hid: 'nuxt-color-mode-script',
globalName: '__NUXT_COLOR_MODE__',
componentName: 'ColorScheme',
classPrefix: '',
classSuffix: '-mode',
storageKey: 'nuxt-color-mode'
},
})
-------->>>>>>>>
In middleware>stats.js
export default function ({ route, redirect }) {
console.log('route', route)
// api call to check further
}
nuxt.config.js
import theme from '#nuxt/content-theme-docs'
export default theme({
docs: {
primaryColor: '#E24F55'
},
modules: ['#nuxtjs/axios'],
router: {
middleware: 'stats'
}
})

Here is a local/jwt example of how to use nuxt-auth in #nuxt/docs theme.
The file structure:
├───components
│ └───global
auth.vue
├───content
│ └───en
playground.md
├───node_modules
├───nuxt.config
├───package.json
├───static
// nuxt.config.js
import theme from "#nuxt/content-theme-docs";
export default theme({
docs: {
primaryColor: "#E24F55",
},
content: {
liveEdit: false,
},
buildModules: ["#nuxtjs/color-mode"],
colorMode: {
preference: "", // default value of $colorMode.preference
fallback: "light", // fallback value if not system preference found
hid: "nuxt-color-mode-script",
globalName: "__NUXT_COLOR_MODE__",
componentName: "ColorScheme",
classPrefix: "",
classSuffix: "-mode",
storageKey: "nuxt-color-mode",
},
// ---->
auth: {
strategies: {
local: {
token: {
property: "token",
// required: true,
// type: 'Bearer'
},
user: {
property: "user",
// autoFetch: true
},
endpoints: {
login: { url: "/api/auth/login", method: "post" },
logout: { url: "/api/auth/logout", method: "post" },
user: { url: "/api/auth/user", method: "get" },
},
},
},
},
// <----
});
// components/global/auth.vue
<template>
<div>
<form #submit.prevent="userLogin">
<div>
<label>Username</label>
<input type="text" v-model="login.username" />
</div>
<div>
<label>Password</label>
<input type="text" v-model="login.password" />
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
login: {
username: '',
password: ''
}
}
},
methods: {
async userLogin() {
try {
let response = await this.$auth.loginWith('local', { data: this.login })
console.log(response)
} catch (err) {
console.log(err)
}
}
}
}
</script>
and in your *.md file use the auth component:
---
title: Playground
description: ''
position: 1
category: Playground
---
<auth></auth>
This example is quite simple. It is only meant to show how to use nuxt auth in the nuxt docs theme.

oh ok, you're right, he can't register the middleware.
But you can create a plugin with beforeEach.
// plugins/guard.js
export default ({ app }) => {
app.router.beforeEach((to,from, next) => {
console.log(to, from)
next()
})
}
// nuxt.config.js
// ...
plugins: [__dirname + '/plugins/guard.js'],
// ...

I've spent some time redacting how to do it. Unfortunately I could not make proper edited and annotated screenshots of the Auth0 (too cumbersome with my current setup to make something clean) but here is my github repo with all the explanations on how to make this work.
https://github.com/kissu/so-nuxt-docs-theme-auth-auth0

Related

Why Nuxt making multiple request for the "user" endpoint?

There is an Express server and a Nuxt client. Nuxt version is 2.15.7.
Entire auth configuration:
// nuxt.config.js
auth: {
plugins: [
{
src: '~/plugins/axios',
ssr: true
},
{
src: '~/plugins/auth'
}
],
cookie: {
prefix: 'auth.',
options: {
path: '/',
secure: process.env.NODE_ENV === 'production' ? true : false
}
},
localStorage: {
prefix: 'auth.'
},
vuex: {
namespace: 'auth'
},
strategies: {
local: {
scheme: 'refresh',
token: {
property: 'accessToken',
maxAge: 900,
global: true,
name: 'Authorization',
type: 'Bearer'
},
refreshToken: {
property: 'refreshToken',
data: 'refreshToken',
maxAge: 5184000
},
user: {
property: 'user',
autoFetch: false
},
endpoints: {
login: {
url: '/user/sign_in',
method: 'post'
},
logout: {
url: '/user/sign_out',
method: 'delete'
},
refresh: {
url: '/user/refresh',
method: 'get'
},
user: {
url: '/user/profile',
method: 'get'
}
}
}
},
redirect: {
login: '/auth/sign_in',
logout: '/',
callback: '/auth/sign_in',
home: '/'
}
}
When I refresh the page in the browser, I see this in the browser log:
This message comes from here:
// plugins/axios.ts
import { AxiosRequestConfig } from 'axios'
export default function ({ $axios, }: any) {
$axios.onRequest((config: AxiosRequestConfig) => {
console.log('Making request to ' + config.url)
})
}
There are also two requests in the server logs. But in the first request I can get, for example, cookies, and in the second one comes this:
// console.log(req.cookies)
[Object: null prototype] {}
Can you please tell me why there are two requests?
The problem was caused by the back end returning this after sign in:
{
"is": 1
}
And should return this:
{
"user": {
"is": 1
}
}
😬
After I added the "user" object, nuxt auth accepted the information and started working correctly.

Nuxt.js auth module does not redirect logged in user

Authenticated user can still access the /login page. If I follow a link to /login page, I am redirected to a different page, which works fine. But if I enter /login into URL manually, I am still being taken to /login page, even though I am already logged in. What I am trying to achieve is, when the user is logged in, they should be redirected to /retailer/account page before any components are shown on the page (if they enter /login page manually).
I was trying using beforeMount() function, beforeCreate() function, following the documentation for auth: 'guest' middleware, however it does not seem to have any effect and loggedIn always returns false before the page is fully rendered.
My setup:
nuxt.config.js :
export default {
mode: 'universal',
target: 'static',
auth: {
cookie: {
prefix: 'auth_'
},
// Options
redirect: {
login: '/login',
logout: '/login',
callback: false,
home: '/retailer/account'
},
strategies: {
local: {
endpoints: {
login: {
url: '/auth/login',
method: 'post',
propertyName: 'access_token',
credentials: true
},
logout: {
url: '/auth/logout',
method: 'post'
},
user: {
url: '/auth/me',
method: 'post',
propertyName: '',
credentials: false
}
},
token: {
required: true,
type: 'Bearer',
global: true
},
autoFetchUser: true
}
},
preserveState: true,
watchLoggedIn: true
},
router: {
middleware: [
'auth'
]
}
}
layouts/default.vue :
export default {
auth: false
}
pages/retailer/account.vue :
export default {
middleware: 'auth'
}
pages/login.vue :
export default {
middleware: 'authenticated',
auth: 'guest'
}
Tried all kinds of middleware examples I could find and made some simple redirection code, but, as mentioned before, app.$auth.loggedIn always returns false from server-side, so I never get redirected.
middleware/authenticated.js
export default function ({ app, redirect }) {
if (app.$auth.loggedIn) {
return redirect(app.localePath({ name: 'index' }))
}
}
Later, when Vue hydrates the app, loggedIn is, of course, true.
Any ideas what I am doing wrong? Any guidance would be a huge help!
Nuxt auth module has a middleware auth can redirect unauthenticated user to login page, and redirect authenticated to home.
I see than the auth middleware is configured correctly in you nuxt.config.js.
The problem is that auth middleware only works on server side for SSR. but you configured to generate static website.
You can remove line target: 'static', from nuxt.config.js.
Or fllow this issue to find some help for static site auth:
https://github.com/nuxt/nuxt.js/issues/3023

CSS is not working with vue js on dynamic routing

I created route in vue
{
path: '/coursedetailed/:id',
component: MyCourseDetailed,
props: true
},
It works, but after I go to the page, it seems that css is disabled. All request are completed component if filled with data. There is one error in console. The other pages works well
Uncaught SyntaxError: Unexpected token <
My vue script for component:
<script>
import axios from 'axios'
import MenuWhite from '#/components/MenuWhite.vue'
export default {
name: 'coursedetailed',
props: ['id'],
components: {
MenuWhite
},
data: () => {
return {
course: [],
errors: []
}
},
created () {
this.getData()
},
methods: {
getData () {
axios({
method: 'get',
url: this.$store.state.endpoints.baseUrl + '/api/courses/' + this.$route.params.id + '/',
withCredentials: true,
headers: {
Authorization: `JWT ${this.$store.state.jwt}`,
'Content-Type': 'application/json'
}
}).then((response) => {
this.course = response.data
})
},
isToken () {
if (this.$store.state.jwt) {
this.$router.push({ path: '/profile' })
} else {
this.$router.push({ path: '/' })
}
}
}
}
Any ideas where the problem may be?
Please check this link.
As it says, a basic Vue component may have a template, a script and a style tag.
Inside the style tag you may put your css directly or import your css file using the #import as you can see here by #Geraldine Golong's answer.
So, my suggestion is to put your css code inside your component (if so, recommend you to put inside your parent component), or import your css file using the proper Vue tag.
Hope it helps.

VUE.js records undefined

I am creating an application where I have a list of users, when I click on a single user, it takes me to that specific users profile (Profile.vue). I am using ASP.NET Core API with Vue.js as my front end. My API is working so when I click on the user, I am able to see the data coming from my database using Chrome dev Tools and Postman. When I open Vue Dev Tools in Chrome, I see that the data is "undefined". For example, I am just trying to get the users firstName to display so I know that its working.
This is how I am routing my page from the list of users to a specific users profile
methods: {
editItem(lastName) {
this.$http.get(`http://localhost:61601/api/GetInquiry/${lastName}`)
this.$router.push({ path: `/Profile/${lastName}` })
},
async GetAllInquiries() {
this.loading = true
try {
this.records = await api.GetAllInquiries()
} finally {
this.loading = false
}
},
Once I am routed, Here is my Profile.Vue that will show the users information
<template>
<div>
<h2>Student Info</h2>
Student Name: {{ records.firstName }}
<br />
</div>
</template>
<script>
import api from '../store/api.js'
export default {
data() {
return {
records: {
firstName: this.firstName
},
}
},
async created() {
this.GetInquiriesByUser()
},
methods: {
async GetInquiriesByUser() {
this.loading = true
},
post: function () {
this.$http.get('http://localhost:61601/api/inquiry', {
firstName: this.firstName
})
}
}
}
</script>
API.js
import Vue from 'vue'
import axios from 'axios'
const client = axios.create({
baseURL: 'http://localhost:61601/api/',
json: true
})
export default {
async execute(method, resource, data) {
return client({
method,
url: resource,
data,
}).then(req => {
return req.data
})
},
GetAllInquiries() {
return this.execute('get', '/Inquiry')
},
GetInquiriesByUser() {
return this.execute('get', '/GetInquiry/')
},
create(data) {
return this.execute('post', '/', data)
},
update(id, data) {
return this.execute('put', `/${id}`, data)
},
delete(id) {
return this.execute('delete', `/${id}`)
}
}
GetInquiryByUser Controller
[Route("api/[controller]")]
public class GetInquiryController : BaseController
{
private GetInquiryByUser manager;
public GetInquiryController(IConfiguration config) : base(config)
{
manager = new GetInquiryByUser(config);
}
[HttpGet("{lastName}")] //api/GetInquiry/yourlastname
public IEnumerable<InquiryModel> Get([FromRoute]string lastName)
{
return manager.GetInquiriesByUser(lastName);
}
}
The Inquiry contoller gets the list of all users and my GetInquiryByUser is passing the lastName to get that specific users profile. (eventually I will pass a unique id, just testing for now)
I am using hash mode for vue routing as well. At first I was confused on what mode I was using and I had a combination of history and hash, but I think I am all hash mode now.
If someone can point me into the right directions, that would be awesome! Please let me know if I need to porvide more details.

Vue-router 2 changes route but does not update the view?

I have a login issue with website that uses:
Vue.js v2.0.3
vue-router v2.0.1
vuex v0.8.2
In routes.js I have a simple interceptor setup
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!router.app.auth.isUserLoggedIn) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
})
And in login.vue,which handles the login page logic after using Google API only for login succeeds I call this:
this.login(userData).then(
() => this.$router.push(this.redirectToAfterLogin), // Login success
() => {} // Login failed
)
mounted: function(){
if (this.auth.isUserLoggedIn){
// Let's just redirect to the main page
this.$router.push(this.redirectToAfterLogins)
}else{
Vue.nextTick(() => {
this.loadGooglePlatform()
})}}
computed: {
redirectToAfterLogin: function() {
if (this.$route.query.redirect){
return this.$route.query.redirect
}else{
return '/'
}
}
}
router.js
var VueRouter = require('vue-router')
// Router setup
export const router = new VueRouter({
linkActiveClass: "is-active",
mode: 'history',
saveScrollPosition: true,
routes: [
{ path: '', name: 'root', redirect: '/home' },
{ path: '/login', name: 'login', meta: { loadingNotRequired: true }, component: require('./pages/login.vue') },
{ path: '/logout', name: 'logout', meta: { loadingNotRequired: true }, component: require('./pages/logout.vue') },
{ path: '/home', name: 'home', title: 'Home', redirect: '/home/random', component: require('./pages/home.vue'),
children: [
{ path: 'random', name: 'random', meta: { requiresAuth: true }, title: 'Random', component: require('./pages/random.vue') }
]
}
]
})
// Redirect to login page if not logged In
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!router.app.auth.isUserLoggedIn) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
})
Now here this.login is just the call to vuex, to update the logged in user.
What happens is that after login, URL changes to /home, but the DOM does not update!
Only way that successfully changed the DOM was forcing location.reload() and that is not what I want to do, as it loses my dynamically loaded G scripts in Head.
Any idea on what to do to force the view to update DOM?
NOTE: it happens only on the first login of user, if he logs out and back-in, the redirecting is fine
Not a perfect solution may be, as it is going to recreate the component but it will work for every case when having same route & needs to update the component.
Just update the <router-view/> or <router-view></router-view> with
<router-view :key="$route.fullPath"></router-view>
Vue re-uses components where possible. You should use beforeRouteUpdate to react to a route switch that uses the same component.
I have the same problem "URL changes to /home, but the DOM does not update".
In my project, the tag "transition" maked the problem.
Hope it is helpful!
Maybe you should set the redirectToAfterLogin function into methods, like this it will be recalculated each times. The computed will be modified only if used v-model changed. To stick to the meaning of the function name, I would set the router push inside.
login.vue :
mounted: function(){
if (this.auth.isUserLoggedIn){
// Let's just redirect to the main page
// this.$router.push(this.redirectToAfterLogins)
this.redirectToAfterLogins()
}else{
Vue.nextTick(() => {
this.loadGooglePlatform()
})
}
},
// computed: {
methods: {
this.login(userData).then(
// () => this.$router.push(this.redirectToAfterLogin), // Login success
() => this.redirectToAfterLogin(), // Login success
() => {} // Login failed
),
redirectToAfterLogin: function() {
if (this.$route.query.redirect){
// return this.$route.query.redirect
this.$router.push(this.$route.query.redirect)
}else{
// return '/'
this.$router.push('/')
}
}
}
https://v2.vuejs.org/v2/guide/computed.html#Computed-Properties
https://v2.vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods
"However, the difference is that computed properties are cached based on their dependencies. A computed property will only re-evaluate when some of its dependencies have changed. This means as long as message has not changed, multiple access to the reversedMessage computed property will immediately return the previously computed result without having to run the function again."
methods vs computed and filters :
Access vue instance/data inside filter method

Categories

Resources