├── .gitignore ├── .prettierrc.js ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ └── logo.png ├── main.js ├── models │ └── user.js ├── router.js ├── services │ ├── auth-header.js │ ├── auth.service.js │ └── user.service.js ├── store │ ├── auth.module.js │ └── index.js └── views │ ├── BoardAdmin.vue │ ├── BoardModerator.vue │ ├── BoardUser.vue │ ├── Home.vue │ ├── Login.vue │ ├── Profile.vue │ └── Register.vue └── vue.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true 3 | }; 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue.js JWT Authentication with Vuex and Vue Router 2 | 3 | For instruction, please visit: 4 | > [Vue 2 JWT Authentication with Vuex and Vue Router](https://bezkoder.com/jwt-vue-vuex-authentication/) 5 | 6 | > [Using Typescript](https://bezkoder.com/vuex-typescript-jwt-auth/) 7 | 8 | > [Vue 3 JWT Authentication with Vuex and Vue Router](https://bezkoder.com/vue-3-authentication-jwt/) 9 | 10 | More Practice: 11 | > [Vue.js CRUD App with Vue Router & Axios](https://bezkoder.com/vue-js-crud-app/) 12 | 13 | > [Vue Pagination with Axios and API example](https://bezkoder.com/vue-pagination-axios/) 14 | 15 | > [Vue File Upload example using Axios](https://bezkoder.com/vue-axios-file-upload/) 16 | 17 | Fullstack with Spring Boot Back-end: 18 | > [Spring Boot + Vue.js: Authentication with JWT & Spring Security Example](https://bezkoder.com/spring-boot-vue-js-authentication-jwt-spring-security/) 19 | 20 | Fullstack with Node.js Express Back-end: 21 | > [Node.js Express + Vue.js: JWT Authentication & Authorization example](https://bezkoder.com/node-express-vue-jwt-auth/) 22 | 23 | Fullstack CRUD: 24 | > [Vue.js + Node.js + Express + MySQL example](https://bezkoder.com/vue-js-node-js-express-mysql-crud-example/) 25 | 26 | > [Vue.js + Node.js + Express + PostgreSQL example](https://bezkoder.com/vue-node-express-postgresql/) 27 | 28 | > [Vue.js + Node.js + Express + MongoDB example](https://bezkoder.com/vue-node-express-mongodb-mevn-crud/) 29 | 30 | > [Vue.js + Spring Boot + MySQL/PostgreSQL example](https://bezkoder.com/spring-boot-vue-js-crud-example/) 31 | 32 | > [Vue.js + Spring Boot + MongoDB example](https://bezkoder.com/spring-boot-vue-mongodb/) 33 | 34 | > [Vue.js + Django example](https://bezkoder.com/django-vue-js-rest-framework/) 35 | 36 | Integration (run back-end & front-end on same server/port) 37 | > [Integrate Vue.js with Spring Boot](https://bezkoder.com/integrate-vue-spring-boot/) 38 | 39 | > [Integrate Vue App with Node.js Express](https://bezkoder.com/serve-vue-app-express/) 40 | 41 | ## Note: 42 | Open `src/services/auth-header.js` and modify `return` statement for appropriate back-end. 43 | 44 | ```js 45 | export default function authHeader() { 46 | let user = JSON.parse(localStorage.getItem('user')); 47 | 48 | if (user && user.accessToken) { 49 | return { Authorization: 'Bearer ' + user.accessToken }; // for Spring Boot back-end 50 | // return { 'x-access-token': user.accessToken }; // for Node.js Express back-end 51 | } else { 52 | return {}; 53 | } 54 | } 55 | ``` 56 | 57 | ## Project setup 58 | ``` 59 | npm install 60 | ``` 61 | 62 | ### Compiles and hot-reloads for development 63 | ``` 64 | npm run serve 65 | ``` 66 | 67 | ### Compiles and minifies for production 68 | ``` 69 | npm run build 70 | ``` 71 | 72 | ### Run your tests 73 | ``` 74 | npm run test 75 | ``` 76 | 77 | ### Lints and fixes files 78 | ``` 79 | npm run lint 80 | ``` 81 | 82 | ### Customize configuration 83 | See [Configuration Reference](https://cli.vuejs.org/config/). 84 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-jwt-example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@fortawesome/fontawesome-svg-core": "^1.2.25", 12 | "@fortawesome/free-solid-svg-icons": "^5.11.2", 13 | "@fortawesome/vue-fontawesome": "^0.1.7", 14 | "axios": "^0.19.0", 15 | "bootstrap": "^4.3.1", 16 | "core-js": "^2.6.5", 17 | "jquery": "^3.4.1", 18 | "popper.js": "^1.15.0", 19 | "vee-validate": "^2.2.15", 20 | "vue": "^2.6.10", 21 | "vue-router": "^3.0.3", 22 | "vuex": "^3.0.1" 23 | }, 24 | "devDependencies": { 25 | "@vue/cli-plugin-babel": "^3.11.0", 26 | "@vue/cli-plugin-eslint": "^3.11.0", 27 | "@vue/cli-service": "^3.11.0", 28 | "babel-eslint": "^10.0.1", 29 | "eslint": "^5.16.0", 30 | "eslint-plugin-vue": "^5.0.0", 31 | "vue-template-compiler": "^2.6.10" 32 | }, 33 | "eslintConfig": { 34 | "root": true, 35 | "env": { 36 | "node": true 37 | }, 38 | "extends": [ 39 | "plugin:vue/essential", 40 | "eslint:recommended" 41 | ], 42 | "rules": {}, 43 | "parserOptions": { 44 | "parser": "babel-eslint" 45 | } 46 | }, 47 | "postcss": { 48 | "plugins": { 49 | "autoprefixer": {} 50 | } 51 | }, 52 | "browserslist": [ 53 | "> 1%", 54 | "last 2 versions" 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3solution/Vue-Vuex-jwt-authenticate/dfc8824625507af635ddeccb866216dc9d0431d2/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | vuejs jwt auth example 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 85 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3solution/Vue-Vuex-jwt-authenticate/dfc8824625507af635ddeccb866216dc9d0431d2/src/assets/logo.png -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import { router } from './router'; 4 | import store from './store'; 5 | import 'bootstrap'; 6 | import 'bootstrap/dist/css/bootstrap.min.css'; 7 | import VeeValidate from 'vee-validate'; 8 | import Vuex from 'vuex'; 9 | import { library } from '@fortawesome/fontawesome-svg-core'; 10 | import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; 11 | import { 12 | faHome, 13 | faUser, 14 | faUserPlus, 15 | faSignInAlt, 16 | faSignOutAlt 17 | } from '@fortawesome/free-solid-svg-icons'; 18 | 19 | library.add(faHome, faUser, faUserPlus, faSignInAlt, faSignOutAlt); 20 | 21 | Vue.config.productionTip = false; 22 | 23 | Vue.use(VeeValidate); 24 | Vue.component('font-awesome-icon', FontAwesomeIcon); 25 | 26 | Vue.use(Vuex); 27 | 28 | new Vue({ 29 | router, 30 | store, 31 | render: h => h(App) 32 | }).$mount('#app'); 33 | -------------------------------------------------------------------------------- /src/models/user.js: -------------------------------------------------------------------------------- 1 | export default class User { 2 | constructor(username, email, password) { 3 | this.username = username; 4 | this.email = email; 5 | this.password = password; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import Home from './views/Home.vue'; 4 | import Login from './views/Login.vue'; 5 | import Register from './views/Register.vue'; 6 | 7 | Vue.use(Router); 8 | 9 | export const router = new Router({ 10 | mode: 'history', 11 | routes: [ 12 | { 13 | path: '/', 14 | name: 'home', 15 | component: Home 16 | }, 17 | { 18 | path: '/home', 19 | component: Home 20 | }, 21 | { 22 | path: '/login', 23 | component: Login 24 | }, 25 | { 26 | path: '/register', 27 | component: Register 28 | }, 29 | { 30 | path: '/profile', 31 | name: 'profile', 32 | // lazy-loaded 33 | component: () => import('./views/Profile.vue') 34 | }, 35 | { 36 | path: '/admin', 37 | name: 'admin', 38 | // lazy-loaded 39 | component: () => import('./views/BoardAdmin.vue') 40 | }, 41 | { 42 | path: '/mod', 43 | name: 'moderator', 44 | // lazy-loaded 45 | component: () => import('./views/BoardModerator.vue') 46 | }, 47 | { 48 | path: '/user', 49 | name: 'user', 50 | // lazy-loaded 51 | component: () => import('./views/BoardUser.vue') 52 | } 53 | ] 54 | }); 55 | 56 | // router.beforeEach((to, from, next) => { 57 | // const publicPages = ['/login', '/register', '/home']; 58 | // const authRequired = !publicPages.includes(to.path); 59 | // const loggedIn = localStorage.getItem('user'); 60 | 61 | // // trying to access a restricted page + not logged in 62 | // // redirect to login page 63 | // if (authRequired && !loggedIn) { 64 | // next('/login'); 65 | // } else { 66 | // next(); 67 | // } 68 | // }); 69 | -------------------------------------------------------------------------------- /src/services/auth-header.js: -------------------------------------------------------------------------------- 1 | export default function authHeader() { 2 | let user = JSON.parse(localStorage.getItem('user')); 3 | 4 | if (user && user.accessToken) { 5 | return { Authorization: 'Bearer ' + user.accessToken }; // for Spring Boot back-end 6 | // return { 'x-access-token': user.accessToken }; // for Node.js Express back-end 7 | } else { 8 | return {}; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/services/auth.service.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | const API_URL = 'http://localhost:8080/api/auth/'; 4 | 5 | class AuthService { 6 | login(user) { 7 | return axios 8 | .post(API_URL + 'signin', { 9 | username: user.username, 10 | password: user.password 11 | }) 12 | .then(response => { 13 | if (response.data.accessToken) { 14 | localStorage.setItem('user', JSON.stringify(response.data)); 15 | } 16 | 17 | return response.data; 18 | }); 19 | } 20 | 21 | logout() { 22 | localStorage.removeItem('user'); 23 | } 24 | 25 | register(user) { 26 | return axios.post(API_URL + 'signup', { 27 | username: user.username, 28 | email: user.email, 29 | password: user.password 30 | }); 31 | } 32 | } 33 | 34 | export default new AuthService(); 35 | -------------------------------------------------------------------------------- /src/services/user.service.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import authHeader from './auth-header'; 3 | 4 | const API_URL = 'http://localhost:8080/api/test/'; 5 | 6 | class UserService { 7 | getPublicContent() { 8 | return axios.get(API_URL + 'all'); 9 | } 10 | 11 | getUserBoard() { 12 | return axios.get(API_URL + 'user', { headers: authHeader() }); 13 | } 14 | 15 | getModeratorBoard() { 16 | return axios.get(API_URL + 'mod', { headers: authHeader() }); 17 | } 18 | 19 | getAdminBoard() { 20 | return axios.get(API_URL + 'admin', { headers: authHeader() }); 21 | } 22 | } 23 | 24 | export default new UserService(); 25 | -------------------------------------------------------------------------------- /src/store/auth.module.js: -------------------------------------------------------------------------------- 1 | import AuthService from '../services/auth.service'; 2 | 3 | const user = JSON.parse(localStorage.getItem('user')); 4 | const initialState = user 5 | ? { status: { loggedIn: true }, user } 6 | : { status: { loggedIn: false }, user: null }; 7 | 8 | export const auth = { 9 | namespaced: true, 10 | state: initialState, 11 | actions: { 12 | login({ commit }, user) { 13 | return AuthService.login(user).then( 14 | user => { 15 | commit('loginSuccess', user); 16 | return Promise.resolve(user); 17 | }, 18 | error => { 19 | commit('loginFailure'); 20 | return Promise.reject(error); 21 | } 22 | ); 23 | }, 24 | logout({ commit }) { 25 | AuthService.logout(); 26 | commit('logout'); 27 | }, 28 | register({ commit }, user) { 29 | return AuthService.register(user).then( 30 | response => { 31 | commit('registerSuccess'); 32 | return Promise.resolve(response.data); 33 | }, 34 | error => { 35 | commit('registerFailure'); 36 | return Promise.reject(error); 37 | } 38 | ); 39 | } 40 | }, 41 | mutations: { 42 | loginSuccess(state, user) { 43 | state.status.loggedIn = true; 44 | state.user = user; 45 | }, 46 | loginFailure(state) { 47 | state.status.loggedIn = false; 48 | state.user = null; 49 | }, 50 | logout(state) { 51 | state.status.loggedIn = false; 52 | state.user = null; 53 | }, 54 | registerSuccess(state) { 55 | state.status.loggedIn = false; 56 | }, 57 | registerFailure(state) { 58 | state.status.loggedIn = false; 59 | } 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | import { auth } from './auth.module'; 5 | 6 | Vue.use(Vuex); 7 | 8 | export default new Vuex.Store({ 9 | modules: { 10 | auth 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /src/views/BoardAdmin.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/BoardModerator.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/BoardUser.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/Login.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 104 | 105 | -------------------------------------------------------------------------------- /src/views/Profile.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | -------------------------------------------------------------------------------- /src/views/Register.vue: -------------------------------------------------------------------------------- 1 | 67 | 68 | 116 | 117 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | devServer: { 3 | port: 8081 4 | } 5 | } --------------------------------------------------------------------------------