finished tutorial
This commit is contained in:
11
notes.md
11
notes.md
@@ -429,6 +429,8 @@ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/imp
|
|||||||
|
|
||||||
https://vueschool.io/articles/vuejs-tutorials/lazy-loading-and-code-splitting-in-vue-js/
|
https://vueschool.io/articles/vuejs-tutorials/lazy-loading-and-code-splitting-in-vue-js/
|
||||||
|
|
||||||
|
### Importing js
|
||||||
|
|
||||||
In javascript you can use several ways to import modules.
|
In javascript you can use several ways to import modules.
|
||||||
|
|
||||||
`import { function } from "module";` is used if you want to import a specific function/class etc from a `.js` file. You can chain the imports with a comma between them. These have to be javascript objects.
|
`import { function } from "module";` is used if you want to import a specific function/class etc from a `.js` file. You can chain the imports with a comma between them. These have to be javascript objects.
|
||||||
@@ -443,3 +445,12 @@ component: () =>
|
|||||||
```
|
```
|
||||||
|
|
||||||
The difference between `require` and `import`: `import` is better to use as it's a function, whereas `require` is a js library. `require` is synchronous but `import` can be asynchronous, and supports lazy loading.
|
The difference between `require` and `import`: `import` is better to use as it's a function, whereas `require` is a js library. `require` is synchronous but `import` can be asynchronous, and supports lazy loading.
|
||||||
|
|
||||||
|
### Importing vue components
|
||||||
|
|
||||||
|
When importing other vue components (e.g vue-lottie) any package that says use `npm install --save` can be substituted with `yarn add`. The `--save` just says to add to the `package.json`.
|
||||||
|
|
||||||
|
If importing vue components that have been downloaded into `node_modules`, you can simply import them like any other component. The `.vue` is optional. e.g.
|
||||||
|
|
||||||
|
Installing is done with `yarn add vue-lottie` and importing in another vue component is done with `import Lottie from "vue-lottie"`.
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"aws-amplify-vue": "^1.1.4",
|
"aws-amplify-vue": "^1.1.4",
|
||||||
"core-js": "^3.6.4",
|
"core-js": "^3.6.4",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
|
"vue-lottie": "^0.2.1",
|
||||||
"vue-router": "^3.1.5",
|
"vue-router": "^3.1.5",
|
||||||
"vuetify": "^2.2.11",
|
"vuetify": "^2.2.11",
|
||||||
"vuex": "^3.1.2"
|
"vuex": "^3.1.2"
|
||||||
|
|||||||
31
src/App.vue
31
src/App.vue
@@ -27,7 +27,10 @@
|
|||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
<br />
|
<br />
|
||||||
<!-- <h1 v-if="this.email != null"> -->
|
<!-- <h1 v-if="this.email != null"> -->
|
||||||
<h1 v-if="this.userEmail != null">Hello {{ this.userEmail }}</h1>
|
<h1 v-if="this.$store.getters.authorized != false">
|
||||||
|
<!-- Hello {{ this.userEmail }} -->
|
||||||
|
Hello {{ this.$store.getters.userEmail }}
|
||||||
|
</h1>
|
||||||
<h1 v-else>Welcome!</h1>
|
<h1 v-else>Welcome!</h1>
|
||||||
<v-col cols="2">
|
<v-col cols="2">
|
||||||
<v-row justify-center>
|
<v-row justify-center>
|
||||||
@@ -47,33 +50,27 @@ import { signOut } from "./utils/auth";
|
|||||||
// import { mapGetters } from "vuex";
|
// import { mapGetters } from "vuex";
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {};
|
||||||
email: null
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {},
|
||||||
userEmail() {
|
|
||||||
return this.$store.state.userEmail
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async created() {
|
async created() {
|
||||||
try {
|
try {
|
||||||
await this.$store.dispatch("fetchUser");
|
await this.$store.dispatch("fetchUser");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
console.log("finally")
|
console.log("finally");
|
||||||
console.log(this.email)
|
console.log(this.email);
|
||||||
console.log(this.$store.state.userEmail)
|
console.log(this.$store.state.userEmail);
|
||||||
// this.email = this.$store.state.userEmail;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async dosignOut() {
|
async dosignOut() {
|
||||||
signOut();
|
try {
|
||||||
this.$store.commit("user", null);
|
await signOut();
|
||||||
this.$store.commit("userEmail", null);
|
} finally {
|
||||||
this.email = this.$store.userEmail;
|
this.$store.dispatch("fetchUser");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
1
src/assets/lottie/delivery.json
Normal file
1
src/assets/lottie/delivery.json
Normal file
File diff suppressed because one or more lines are too long
1
src/assets/lottie/halloween.json
Normal file
1
src/assets/lottie/halloween.json
Normal file
File diff suppressed because one or more lines are too long
23
src/components/Animation.vue
Normal file
23
src/components/Animation.vue
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<lottie :options="defaultOptions" :height="400" :width="400"> </lottie>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Lottie from "vue-lottie";
|
||||||
|
import * as delivery from "../assets/lottie/delivery.json";
|
||||||
|
// console.log(delivery)
|
||||||
|
export default {
|
||||||
|
name: "Animation",
|
||||||
|
components: {
|
||||||
|
lottie: Lottie
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
defaultOptions: { animationData: delivery.default },
|
||||||
|
animationSpeed: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -5,10 +5,14 @@ import store from "./store";
|
|||||||
import vuetify from "./plugins/vuetify";
|
import vuetify from "./plugins/vuetify";
|
||||||
import Amplify from "aws-amplify";
|
import Amplify from "aws-amplify";
|
||||||
import awsconfig from "./aws-exports";
|
import awsconfig from "./aws-exports";
|
||||||
|
import Lottie from "vue-lottie";
|
||||||
|
|
||||||
Amplify.configure(awsconfig);
|
Amplify.configure(awsconfig);
|
||||||
Vue.use(Amplify);
|
Vue.use(Amplify);
|
||||||
|
|
||||||
|
Vue.component("lottie", Lottie);
|
||||||
|
console.log(Lottie);
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ const routes = [
|
|||||||
// this generates a separate chunk (about.[hash].js) for this route
|
// this generates a separate chunk (about.[hash].js) for this route
|
||||||
// which is lazy-loaded when the route is visited.
|
// which is lazy-loaded when the route is visited.
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "about" */ "../views/About.vue")
|
import(/* webpackChunkName: "about" */ "../views/About.vue"),
|
||||||
|
// meta: { requiresAuth: false }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/signUp",
|
path: "/signUp",
|
||||||
@@ -52,7 +53,7 @@ const router = new VueRouter({
|
|||||||
});
|
});
|
||||||
|
|
||||||
getUser().then(user => {
|
getUser().then(user => {
|
||||||
console.log("router getting user.")
|
console.log("router getting user.");
|
||||||
if (user) {
|
if (user) {
|
||||||
router.push({ path: "/" });
|
router.push({ path: "/" });
|
||||||
}
|
}
|
||||||
@@ -82,7 +83,7 @@ AmplifyEventBus.$on("authState", async state => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.beforeResolve(async (to, _from, next) => {
|
router.beforeResolve(async (to, _from, next) => {
|
||||||
console.log("router before resolve getting current user.")
|
console.log("router before resolve getting current user.");
|
||||||
const user = await getUser();
|
const user = await getUser();
|
||||||
if (!user) {
|
if (!user) {
|
||||||
if (to.matched.some(record => record.meta.requiresAuth)) {
|
if (to.matched.some(record => record.meta.requiresAuth)) {
|
||||||
|
|||||||
@@ -37,11 +37,14 @@ const store = new Vuex.Store({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
modules: {},
|
modules: {},
|
||||||
// getters: {
|
getters: {
|
||||||
// userEmail: state => {
|
userEmail: state => {
|
||||||
// return state.userEmail;
|
return state.userEmail;
|
||||||
// }
|
},
|
||||||
// }
|
authorized: state => {
|
||||||
|
return state.authorized;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// store.dispatch.fetchUser()
|
// store.dispatch.fetchUser()
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ async function signIn(username, password) {
|
|||||||
try {
|
try {
|
||||||
console.log("Attempting sign in");
|
console.log("Attempting sign in");
|
||||||
const user = await Auth.signIn(username, password);
|
const user = await Auth.signIn(username, password);
|
||||||
AmplifyEventBus.$emit("authState", "signedIn");
|
|
||||||
console.log("Signed in in fn");
|
console.log("Signed in in fn");
|
||||||
console.log(user);
|
console.log(user);
|
||||||
if (user) {
|
if (user) {
|
||||||
|
|||||||
@@ -1,5 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="about">
|
<div class="about">
|
||||||
<h1>This is an about page</h1>
|
<h1>This is an about page</h1>
|
||||||
|
<!-- <br /> -->
|
||||||
|
<v-card class="d-inline-flex">
|
||||||
|
<animation></animation>
|
||||||
|
</v-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Animation from "../components/Animation";
|
||||||
|
// import Lottie from "vue-lottie";
|
||||||
|
import * as delivery from "@/assets/lottie/halloween.json";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
animation: Animation
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleAnimation: function(anim) {
|
||||||
|
this.anim = anim;
|
||||||
|
},
|
||||||
|
|
||||||
|
stop: function() {
|
||||||
|
this.anim.stop();
|
||||||
|
},
|
||||||
|
|
||||||
|
play: function() {
|
||||||
|
this.anim.play();
|
||||||
|
},
|
||||||
|
|
||||||
|
pause: function() {
|
||||||
|
this.anim.pause();
|
||||||
|
},
|
||||||
|
|
||||||
|
onSpeedChange: function() {
|
||||||
|
this.anim.setSpeed(this.animationSpeed);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
defaultOptions: { animationData: delivery },
|
||||||
|
animationSpeed: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
@@ -1,11 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- <h1>Hello {{ this.$store.getters.userEmail }}</h1> -->
|
<v-btn rounded color="primary" class="padme" @click="showJWT"
|
||||||
|
>Show JWT</v-btn
|
||||||
|
>
|
||||||
|
<h1 style=""></h1>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { Auth } from "aws-amplify";
|
||||||
|
import Lottie from "vue-lottie";
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
jwt: "",
|
||||||
|
tempHeaders: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async showJWT() {
|
||||||
|
try {
|
||||||
|
this.jwt = await Auth.currentSession();
|
||||||
|
this.tempHeaders = {
|
||||||
|
Authorization: `Bearer ${(await Auth.currentSession())
|
||||||
|
.getIdToken()
|
||||||
|
.getJwtToken()}`
|
||||||
|
};
|
||||||
|
} finally {
|
||||||
|
console.log(this.jwt);
|
||||||
|
let id = this.jwt.getIdToken();
|
||||||
|
console.log(id);
|
||||||
|
let jwt = id.getJwtToken();
|
||||||
|
console.log(jwt);
|
||||||
|
console.log(this.tempHeaders)
|
||||||
|
alert(this.tempHeaders.Authorization)
|
||||||
|
console.log(Lottie)
|
||||||
|
// alert(this.jwt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped>
|
||||||
|
.padme {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
134
src/views/Untitled-5.md
Normal file
134
src/views/Untitled-5.md
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
# Managing sign in/out + displaying name
|
||||||
|
|
||||||
|
## Create the Vuex store
|
||||||
|
|
||||||
|
### state
|
||||||
|
|
||||||
|
Your state should contain 3 items:
|
||||||
|
|
||||||
|
- authorized:bool = flag if logged in or not.
|
||||||
|
- user: str = user object.
|
||||||
|
- userEmail: str = username or email.
|
||||||
|
|
||||||
|
### mutations
|
||||||
|
|
||||||
|
You should define two mutations (to update this state):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
mutations: {
|
||||||
|
user(state, user) {
|
||||||
|
state.authorized =
|
||||||
|
!!user && user.attributes && user.attributes.email_verified;
|
||||||
|
state.user = user;
|
||||||
|
},
|
||||||
|
userEmail(state, userEmail) {
|
||||||
|
state.userEmail = userEmail;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
- When you set the user state you should check to make sure the user object you pass in exists and set the authorized flag at the same time.
|
||||||
|
|
||||||
|
### actions
|
||||||
|
|
||||||
|
You should define an action that fetches the user. This should call the `getUser` method of whatever auth system you're using and pass this in to the method.
|
||||||
|
|
||||||
|
This `getUser` dispatch should either get the user and set the store state, or set it to null if no user exists. This way, any interaction with `getUser` will make sure the store is up to date.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
actions: {
|
||||||
|
async fetchUser({ commit }) {
|
||||||
|
try {
|
||||||
|
const user = await Auth.currentAuthenticatedUser();
|
||||||
|
const expires =
|
||||||
|
user.getSignInUserSession().getIdToken().payload.exp -
|
||||||
|
Math.floor(new Date().getTime() / 1000);
|
||||||
|
console.log(`Token expires in ${expires} seconds.`);
|
||||||
|
commit("user", user);
|
||||||
|
commit("userEmail", user.attributes.email);
|
||||||
|
} catch (err) {
|
||||||
|
commit("user", null);
|
||||||
|
commit("userEmail", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
### getters
|
||||||
|
|
||||||
|
You should define getters to access the state. These getters will cache - so they will only update if one of the things used to calculate the state updates.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
getters: {
|
||||||
|
userEmail: state => {
|
||||||
|
return state.userEmail;
|
||||||
|
},
|
||||||
|
authorized: state => {
|
||||||
|
return state.authorized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Triggering state for apps
|
||||||
|
|
||||||
|
In addition to getting the user to determine router actions, you should get the user in the main component so you can set the state.
|
||||||
|
|
||||||
|
In the main view (parent of all components `App.vue`) you should define a `created` method. This method should:
|
||||||
|
|
||||||
|
- Fetch the user.
|
||||||
|
- Change the state to reflect this.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async created() {
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch("fetchUser");
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
console.log(this.email);
|
||||||
|
console.log(this.$store.state.userEmail);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
This needs to be done right at the start to make sure this triggers a state change before anything else.
|
||||||
|
|
||||||
|
In the views for signing in/out/registering etc you should make sure that when you call the auth methods you wrote, that you also update the state at this time.
|
||||||
|
This way, any component in the app can use the state to determine if someone is logged in, and display/toggle components dynamically.
|
||||||
|
|
||||||
|
A signin method for a button might look like:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async submit() {
|
||||||
|
if (this.$refs.form.validate()) {
|
||||||
|
console.log(
|
||||||
|
`SIGN IN username: ${this.username}, password: ${this.password}`
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await signIn(this.username, this.password);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
} finally {
|
||||||
|
this.$store.dispatch("fetchUser");
|
||||||
|
}
|
||||||
|
console.log("Signed in");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A sign out button might look like:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async dosignOut() {
|
||||||
|
try {
|
||||||
|
await signOut();
|
||||||
|
} finally {
|
||||||
|
this.$store.dispatch("fetchUser");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Remember:
|
||||||
|
|
||||||
|
- Call `this.$store.dispatch("fetchUser)` when you sign in - do it in a try/finally block to make sure the state gets updated after the ajax call.
|
||||||
|
- Call `this.$store.dispatch("fetchUser)` when you sign out do it in a try/finally bock to make sure the state gets updated after the ajax call.
|
||||||
252
tutorial.md
252
tutorial.md
@@ -1,3 +1,13 @@
|
|||||||
|
# AWS amplify
|
||||||
|
|
||||||
|
## Example repo
|
||||||
|
|
||||||
|
Use the following repo as an example/baseline:
|
||||||
|
|
||||||
|
<https://git.panaetius.co.uk/web-development/medium-aws-tutorial-1>
|
||||||
|
|
||||||
|
## Installaing amplify
|
||||||
|
|
||||||
Install amplify globally
|
Install amplify globally
|
||||||
|
|
||||||
`yarn global add @aws-amplify/cli`
|
`yarn global add @aws-amplify/cli`
|
||||||
@@ -6,6 +16,8 @@ Create new amplify app in project
|
|||||||
|
|
||||||
`amplify init`
|
`amplify init`
|
||||||
|
|
||||||
|
### Amplify commands
|
||||||
|
|
||||||
Amplify commands after init
|
Amplify commands after init
|
||||||
|
|
||||||
`amplify status` - will show you what you've added already and if it's locally configured or deployed
|
`amplify status` - will show you what you've added already and if it's locally configured or deployed
|
||||||
@@ -20,7 +32,12 @@ Amplify commands after init
|
|||||||
Install aws amplify dependencies into project
|
Install aws amplify dependencies into project
|
||||||
`yarn add aws-amplify aws-amplify-vue`
|
`yarn add aws-amplify aws-amplify-vue`
|
||||||
|
|
||||||
|
## Create auth flow
|
||||||
|
|
||||||
Add the Amplify instance to Vue instance in `main.js`
|
Add the Amplify instance to Vue instance in `main.js`
|
||||||
|
|
||||||
|
### Auth.js
|
||||||
|
|
||||||
Create a new js file in `./src/utils/auth.js` - write the aws amplify code in here.
|
Create a new js file in `./src/utils/auth.js` - write the aws amplify code in here.
|
||||||
|
|
||||||
You need to write a function for each auth flow. Signup, GetUser etc.
|
You need to write a function for each auth flow. Signup, GetUser etc.
|
||||||
@@ -28,3 +45,238 @@ You need to write a function for each auth flow. Signup, GetUser etc.
|
|||||||
Remember to use
|
Remember to use
|
||||||
`export {getUser, signUp, confirmSignUp, resendSignUp, signIn, signOut}`
|
`export {getUser, signUp, confirmSignUp, resendSignUp, signIn, signOut}`
|
||||||
at the end so it can be imported later.
|
at the end so it can be imported later.
|
||||||
|
|
||||||
|
You should write a view for each action, login, signup etc.
|
||||||
|
These views should define the UI, and also call the function in the `auth.js`. E.g if you need to sign in, you should write the UI, write any computed methods to verify the form, and write a submit method that takes the form details and calls the `signIn` function from the `auth.js` file.
|
||||||
|
|
||||||
|
In `./utils/auth.js` you can write the functions needed to actually log in with amplify.
|
||||||
|
|
||||||
|
For example, to signUp you can do:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function signUp(username, password) {
|
||||||
|
return Auth.signUp({
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
attributes: {
|
||||||
|
email: username
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
AmplifyEventBus.$emit("localUser", data.user);
|
||||||
|
if (data.userConfirmed === false) {
|
||||||
|
AmplifyEventBus.$emit("authState", "confirmSignUp");
|
||||||
|
} else {
|
||||||
|
AmplifyEventBus.$emit("authState", "signIn");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### router/index.js
|
||||||
|
|
||||||
|
In the `./router/index.js` you should write the router flow.
|
||||||
|
|
||||||
|
#### Define routes
|
||||||
|
|
||||||
|
Each route should set whether they need authentication or not.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
name: "Home",
|
||||||
|
component: Home,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Additional functionality
|
||||||
|
|
||||||
|
In this file, you can write functions that control the behaviour. For example, you can force anyone logged in to go to the home page only:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
getUser().then(user => {
|
||||||
|
if (user) {
|
||||||
|
router.push({ path: "/" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Respond to events
|
||||||
|
|
||||||
|
AWS Amplify has the ability to natively `emit` events in your auth flow functions. When you emit these, you can use `AmplifyEventBus` to do something.
|
||||||
|
|
||||||
|
We can push people to different routes based on the sign in flow.
|
||||||
|
|
||||||
|
An example emit:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
AmplifyEventBus.$emit("authState", "signedIn");
|
||||||
|
```
|
||||||
|
|
||||||
|
An example listener in the router:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
AmplifyEventBus.$on("authState", async state => {
|
||||||
|
const pushPathes = {
|
||||||
|
signedOut: () => {
|
||||||
|
router.push({ path: "/signIn" });
|
||||||
|
},
|
||||||
|
signUp: () => {
|
||||||
|
router.push({ path: "/signUp" });
|
||||||
|
},
|
||||||
|
confirmSignUp: () => {
|
||||||
|
router.push({ path: "/signUpConfirm" });
|
||||||
|
},
|
||||||
|
signIn: () => {
|
||||||
|
router.push({ path: "/signIn" });
|
||||||
|
},
|
||||||
|
signedIn: () => {
|
||||||
|
router.push({ path: "/" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (typeof pushPathes[state] === "function") {
|
||||||
|
pushPathes[state]();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Managing sign in/out + displaying name
|
||||||
|
|
||||||
|
### Create the Vuex store
|
||||||
|
|
||||||
|
#### state
|
||||||
|
|
||||||
|
Your state should contain 3 items:
|
||||||
|
|
||||||
|
- authorized:bool = flag if logged in or not.
|
||||||
|
- user: str = user object.
|
||||||
|
- userEmail: str = username or email.
|
||||||
|
|
||||||
|
#### mutations
|
||||||
|
|
||||||
|
You should define two mutations (to update this state):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
mutations: {
|
||||||
|
user(state, user) {
|
||||||
|
state.authorized =
|
||||||
|
!!user && user.attributes && user.attributes.email_verified;
|
||||||
|
state.user = user;
|
||||||
|
},
|
||||||
|
userEmail(state, userEmail) {
|
||||||
|
state.userEmail = userEmail;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
- When you set the user state you should check to make sure the user object you pass in exists and set the authorized flag at the same time.
|
||||||
|
|
||||||
|
#### actions
|
||||||
|
|
||||||
|
You should define an action that fetches the user. This should call the `getUser` method of whatever auth system you're using and pass this in to the method.
|
||||||
|
|
||||||
|
This `getUser` dispatch should either get the user and set the store state, or set it to null if no user exists. This way, any interaction with `getUser` will make sure the store is up to date.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
actions: {
|
||||||
|
async fetchUser({ commit }) {
|
||||||
|
try {
|
||||||
|
const user = await Auth.currentAuthenticatedUser();
|
||||||
|
const expires =
|
||||||
|
user.getSignInUserSession().getIdToken().payload.exp -
|
||||||
|
Math.floor(new Date().getTime() / 1000);
|
||||||
|
console.log(`Token expires in ${expires} seconds.`);
|
||||||
|
commit("user", user);
|
||||||
|
commit("userEmail", user.attributes.email);
|
||||||
|
} catch (err) {
|
||||||
|
commit("user", null);
|
||||||
|
commit("userEmail", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
#### getters
|
||||||
|
|
||||||
|
You should define getters to access the state. These getters will cache - so they will only update if one of the things used to calculate the state updates.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
getters: {
|
||||||
|
userEmail: state => {
|
||||||
|
return state.userEmail;
|
||||||
|
},
|
||||||
|
authorized: state => {
|
||||||
|
return state.authorized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Triggering state for apps
|
||||||
|
|
||||||
|
In addition to getting the user to determine router actions, you should get the user in the main component so you can set the state.
|
||||||
|
|
||||||
|
In the main view (parent of all components `App.vue`) you should define a `created` method. This method should:
|
||||||
|
|
||||||
|
- Fetch the user.
|
||||||
|
- Change the state to reflect this.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async created() {
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch("fetchUser");
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
console.log(this.email);
|
||||||
|
console.log(this.$store.state.userEmail);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
This needs to be done right at the start to make sure this triggers a state change before anything else.
|
||||||
|
|
||||||
|
In the views for signing in/out/registering etc you should make sure that when you call the auth methods you wrote, that you also update the state at this time.
|
||||||
|
This way, any component in the app can use the state to determine if someone is logged in, and display/toggle components dynamically.
|
||||||
|
|
||||||
|
A signin method for a button might look like:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async submit() {
|
||||||
|
if (this.$refs.form.validate()) {
|
||||||
|
console.log(
|
||||||
|
`SIGN IN username: ${this.username}, password: ${this.password}`
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await signIn(this.username, this.password);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
} finally {
|
||||||
|
this.$store.dispatch("fetchUser");
|
||||||
|
}
|
||||||
|
console.log("Signed in");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A sign out button might look like:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async dosignOut() {
|
||||||
|
try {
|
||||||
|
await signOut();
|
||||||
|
} finally {
|
||||||
|
this.$store.dispatch("fetchUser");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Remember:
|
||||||
|
|
||||||
|
- Call `this.$store.dispatch("fetchUser)` when you sign in - do it in a try/finally block to make sure the state gets updated after the ajax call.
|
||||||
|
- Call `this.$store.dispatch("fetchUser)` when you sign out do it in a try/finally bock to make sure the state gets updated after the ajax call.
|
||||||
|
|||||||
12
yarn.lock
12
yarn.lock
@@ -7653,6 +7653,11 @@ loose-envify@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
js-tokens "^3.0.0 || ^4.0.0"
|
js-tokens "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
|
lottie-web@^5.1.9:
|
||||||
|
version "5.6.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/lottie-web/-/lottie-web-5.6.6.tgz#106fa3dc54337588517591b2e3e348248c6a3f1b"
|
||||||
|
integrity sha512-N2c5+VjWFFEv8AQIDohFQaFiPudcSTSKE6WrMmUqtjc+/tQWe23eTu7XHqzXuAf7HDQclHhBorDeSelPNaYiHQ==
|
||||||
|
|
||||||
lower-case-first@^1.0.0:
|
lower-case-first@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1"
|
resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1"
|
||||||
@@ -11524,6 +11529,13 @@ vue-loader@^15.8.3:
|
|||||||
vue-hot-reload-api "^2.3.0"
|
vue-hot-reload-api "^2.3.0"
|
||||||
vue-style-loader "^4.1.0"
|
vue-style-loader "^4.1.0"
|
||||||
|
|
||||||
|
vue-lottie@^0.2.1:
|
||||||
|
version "0.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-lottie/-/vue-lottie-0.2.1.tgz#f9f62c34a276e6834255406118fb05b51f765e4b"
|
||||||
|
integrity sha512-zInUX69Ij8MhVR3XArpu4PqqBoufwKxS5UMutWCPm59VUaB5H6GtnaIzf9M+l6aYU+Kr8gF/W9dzWLgRuU6V+Q==
|
||||||
|
dependencies:
|
||||||
|
lottie-web "^5.1.9"
|
||||||
|
|
||||||
vue-router@^3.1.5:
|
vue-router@^3.1.5:
|
||||||
version "3.1.6"
|
version "3.1.6"
|
||||||
resolved "https://registry.npm.taobao.org/vue-router/download/vue-router-3.1.6.tgz#45f5a3a3843e31702c061dd829393554e4328f89"
|
resolved "https://registry.npm.taobao.org/vue-router/download/vue-router-3.1.6.tgz#45f5a3a3843e31702c061dd829393554e4328f89"
|
||||||
|
|||||||
Reference in New Issue
Block a user