add login and token !
This commit is contained in:
parent
b28c897f5d
commit
0cf8ca8597
21
hn-vue/package-lock.json
generated
21
hn-vue/package-lock.json
generated
@ -9500,6 +9500,11 @@
|
|||||||
"integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
|
"integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"shvl": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/shvl/-/shvl-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-G3KkIXPza3dgkt6Bo8zIl5K/KvAAhbG6o9KfAjhPvrIIzzAhnfc2ztv1i+iPTbNNM43MaBUqIaZwqVjkSgY/rw=="
|
||||||
|
},
|
||||||
"signal-exit": {
|
"signal-exit": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
|
||||||
@ -11031,6 +11036,22 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.0.tgz",
|
||||||
"integrity": "sha512-W74OO2vCJPs9/YjNjW8lLbj+jzT24waTo2KShI8jLvJW8OaIkgb3wuAMA7D+ZiUxDOx3ubwSZTaJBip9G8a3aQ=="
|
"integrity": "sha512-W74OO2vCJPs9/YjNjW8lLbj+jzT24waTo2KShI8jLvJW8OaIkgb3wuAMA7D+ZiUxDOx3ubwSZTaJBip9G8a3aQ=="
|
||||||
},
|
},
|
||||||
|
"vuex-persistedstate": {
|
||||||
|
"version": "4.0.0-beta.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/vuex-persistedstate/-/vuex-persistedstate-4.0.0-beta.3.tgz",
|
||||||
|
"integrity": "sha512-T4IRD27qoUWh+8qr6T6zVp15xO7x/nPgnU13OD0C2uUwA7U9PhGozrj6lvVmMYDyRgc36J0msMXn3GvwHjkIhA==",
|
||||||
|
"requires": {
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"shvl": "^2.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"deepmerge": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"watchpack": {
|
"watchpack": {
|
||||||
"version": "1.7.5",
|
"version": "1.7.5",
|
||||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
|
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
|
||||||
|
|||||||
@ -12,7 +12,8 @@
|
|||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-router": "^3.4.9",
|
"vue-router": "^3.4.9",
|
||||||
"vuelidate": "^0.7.6",
|
"vuelidate": "^0.7.6",
|
||||||
"vuex": "^3.6.0"
|
"vuex": "^3.6.0",
|
||||||
|
"vuex-persistedstate": "^4.0.0-beta.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "~4.5.0",
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
<router-link :to="{ name: 'links' }">Derniers liens publiés</router-link>
|
<router-link :to="{ name: 'links' }">Derniers liens publiés</router-link>
|
||||||
/
|
/
|
||||||
<router-link :to="{ name: 'register' }">Créer un compte</router-link>
|
<router-link :to="{ name: 'register' }">Créer un compte</router-link>
|
||||||
|
/
|
||||||
|
<router-link :to="{ name: 'login' }">Se connecter</router-link>
|
||||||
</nav>
|
</nav>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
<notifications-panel />
|
<notifications-panel />
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
class Api {
|
class Api {
|
||||||
constructor(baseUrl) {
|
constructor(baseUrl) {
|
||||||
this.baseUrl = baseUrl;
|
this._baseUrl = baseUrl;
|
||||||
|
this._getToken = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
useToken(cb) {
|
||||||
|
this._getToken = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
getLinks() {
|
getLinks() {
|
||||||
@ -19,10 +24,29 @@ class Api {
|
|||||||
return this._post("/api/accounts", data);
|
return this._post("/api/accounts", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
login(data) {
|
||||||
|
return this._post("/api/accounts/token", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
_authorizationHeader() {
|
||||||
|
if (!this._getToken) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = this._getToken();
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { Authorization: `Bearer ${token}` };
|
||||||
|
}
|
||||||
|
|
||||||
_get(path) {
|
_get(path) {
|
||||||
return fetch(this.baseUrl + path, {
|
return fetch(this._baseUrl + path, {
|
||||||
headers: {
|
headers: {
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
|
...this._authorizationHeader(),
|
||||||
},
|
},
|
||||||
}).then((r) => {
|
}).then((r) => {
|
||||||
if (!r.ok) {
|
if (!r.ok) {
|
||||||
@ -34,11 +58,12 @@ class Api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_post(path, data) {
|
_post(path, data) {
|
||||||
return fetch(this.baseUrl + path, {
|
return fetch(this._baseUrl + path, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
...this._authorizationHeader(),
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
}).then((r) => {
|
}).then((r) => {
|
||||||
@ -50,6 +75,8 @@ class Api {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (!r.headers['Content-Length'] === '0') {
|
||||||
|
|
||||||
return r.json();
|
return r.json();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import { mapState } from "vuex";
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["messages"]),
|
...mapState("notification", ["messages"]),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import Layout from "./Layout.vue";
|
|||||||
import createRouter from "./router";
|
import createRouter from "./router";
|
||||||
import createStore from "./store";
|
import createStore from "./store";
|
||||||
import Notifications from "./plugins/Notifications";
|
import Notifications from "./plugins/Notifications";
|
||||||
|
import api from "./api";
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
Vue.use(Vuelidate);
|
Vue.use(Vuelidate);
|
||||||
@ -12,6 +13,8 @@ Vue.use(Notifications);
|
|||||||
const router = createRouter();
|
const router = createRouter();
|
||||||
const store = createStore();
|
const store = createStore();
|
||||||
|
|
||||||
|
api.useToken(() => store.state.auth.token);
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
router,
|
router,
|
||||||
store,
|
store,
|
||||||
|
|||||||
52
hn-vue/src/pages/Login.vue
Normal file
52
hn-vue/src/pages/Login.vue
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1>Connexion</h1>
|
||||||
|
<form @submit.prevent="login">
|
||||||
|
<error v-if="err" :error="err" />
|
||||||
|
<textfield label="Nom d'utilisteur" :field="$v.username" />
|
||||||
|
<textfield label="Mot de passe" type="password" :field="$v.password" />
|
||||||
|
|
||||||
|
<button type="submit" :disabled="$v.$invalid">Se connecter</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Textfield from "../components/Textfield";
|
||||||
|
import Error from "../components/Error";
|
||||||
|
import { required } from "vuelidate/lib/validators";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { Textfield, Error },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
err: null,
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async login() {
|
||||||
|
this.err = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch("auth/login", {
|
||||||
|
username: this.username,
|
||||||
|
password: this.password,
|
||||||
|
});
|
||||||
|
this.$redirectWithMessage({ name: "links" }, "Vous êtes authentifié !");
|
||||||
|
} catch (e) {
|
||||||
|
this.err = e;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validations: {
|
||||||
|
username: {
|
||||||
|
required,
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
required,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@ -1,7 +1,7 @@
|
|||||||
export default {
|
export default {
|
||||||
install(Vue) {
|
install(Vue) {
|
||||||
Vue.prototype.$message = function(message) {
|
Vue.prototype.$message = function(message) {
|
||||||
this.$store.dispatch("addMessage", message);
|
this.$store.dispatch("notification/addMessage", message);
|
||||||
};
|
};
|
||||||
|
|
||||||
Vue.prototype.$redirectWithMessage = function(to, message) {
|
Vue.prototype.$redirectWithMessage = function(to, message) {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import Vue from "vue";
|
|||||||
import VueRouter from "vue-router";
|
import VueRouter from "vue-router";
|
||||||
import Links from "./pages/Links.vue";
|
import Links from "./pages/Links.vue";
|
||||||
import Register from "./pages/Register.vue";
|
import Register from "./pages/Register.vue";
|
||||||
|
import Login from "./pages/Login.vue";
|
||||||
import LinkDetail from "./pages/LinkDetail.vue";
|
import LinkDetail from "./pages/LinkDetail.vue";
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
@ -17,6 +18,7 @@ export default function createRouter() {
|
|||||||
props: true,
|
props: true,
|
||||||
},
|
},
|
||||||
{ path: "/register", name: "register", component: Register },
|
{ path: "/register", name: "register", component: Register },
|
||||||
|
{ path: "/login", name: "login", component: Login },
|
||||||
{ path: "*", redirect: "/" },
|
{ path: "*", redirect: "/" },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,27 +1,58 @@
|
|||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import Vuex from "vuex";
|
import Vuex from "vuex";
|
||||||
|
import createPersistedState from "vuex-persistedstate";
|
||||||
|
import api from "./api";
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
export default function createStore() {
|
export default function createStore() {
|
||||||
return new Vuex.Store({
|
return new Vuex.Store({
|
||||||
state: {
|
modules: {
|
||||||
messages: [],
|
notification: {
|
||||||
},
|
namespaced: true,
|
||||||
mutations: {
|
state: {
|
||||||
pushMessage(state, message) {
|
messages: [],
|
||||||
state.messages = [...state.messages, message];
|
},
|
||||||
},
|
mutations: {
|
||||||
removeMessage(state, message) {
|
pushMessage(state, message) {
|
||||||
state.messages = state.messages.filter((m) => m !== message);
|
state.messages = [...state.messages, message];
|
||||||
},
|
},
|
||||||
},
|
removeMessage(state, message) {
|
||||||
actions: {
|
state.messages = state.messages.filter((m) => m !== message);
|
||||||
addMessage({ commit }, message) {
|
},
|
||||||
commit("pushMessage", message);
|
},
|
||||||
|
actions: {
|
||||||
|
addMessage({ commit }, message) {
|
||||||
|
commit("pushMessage", message);
|
||||||
|
|
||||||
setTimeout(() => commit("removeMessage", message), 3000);
|
setTimeout(() => commit("removeMessage", message), 3000);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
auth: {
|
||||||
|
namespaced: true,
|
||||||
|
state: {
|
||||||
|
token: null,
|
||||||
|
username: null,
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
setUser(state, { token, username }) {
|
||||||
|
state.token = token;
|
||||||
|
state.username = username;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
async login({ commit }, data) {
|
||||||
|
const result = await api.login(data);
|
||||||
|
commit("setUser", result);
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
plugins: [
|
||||||
|
createPersistedState({
|
||||||
|
paths: ["auth"],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user