Vue3のComposition APIでCognito認証したい 後編
概要
Vue3のComposition APIでCognito認証したい 前編の続き。
前回はamplifyコマンドを使って、CloudFormationの設定とvueプロジェクトのセットアップを行った。
Cognito認証管理クラスを作る
認証関連機能を持ったクラスを作成。
準備
src/plugins/cognito-authenticator/index.ts
を作成。
class CognitoAuthenticator {
// ここに実装していく
}
// インスタンスをエクスポート
export const cognitoAuthenticator = new CognitoAuthenticator()
接続準備(コンストラクタ)
必要そうなものをimportして、Cognito認証をするための初期セットアップを行う。
import authAwsConfig from "@/aws-exports";
import {
AuthenticationDetails,
CognitoUser,
CognitoUserAttribute,
CognitoUserPool,
CognitoUserSession
} from "amazon-cognito-identity-js";
import Aws from "aws-sdk";
class CognitoAuthenticator {
private userpool: CognitoUserPool;
constructor() {
console.log("cognitoAuthenticatorClass - constructor");
this.userpool = new CognitoUserPool({
UserPoolId: authAwsConfig.aws_user_pools_id,
ClientId: authAwsConfig.aws_user_pools_web_client_id
});
Aws.config.update({
region: authAwsConfig.aws_cognito_region,
credentials: new Aws.CognitoIdentityCredentials({
IdentityPoolId: authAwsConfig.aws_cognito_identity_pool_id
})
});
}
get currentUser() {
return this.userpool.getCurrentUser();
}
}
Signin / Signout
サインインとサインアウトの処理。 ユーザーをAWSコンソールで作った場合、新たなパスワードを設定する必要がある。 また、サインアップ時の必須属性にNameを設定したのでそのパラメータが必要になる。
このコードでは決め打ちしているけどパスワードは入力したほうが良いし、必要な属性はrequiredAttributes
から取得したほうが良いと思う。
class CognitoAuthenticator {
/* 省略 */
signin(email: string, password: string) {
const cognitoUser = new CognitoUser({
Username: email,
Pool: this.userpool
});
const authenticationDetails = new AuthenticationDetails({
Username: email,
Password: password
});
return new Promise<CognitoUserSession>((resolve, reject) => {
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: result => {
resolve(result);
},
onFailure: error => {
reject(error);
},
// eslint-disable-next-line
newPasswordRequired: (userAttributes, requiredAttributes) => {
cognitoUser.completeNewPasswordChallenge(
password,
{ name: "ZAKI" },
{
onSuccess: result => {
resolve(result);
},
onFailure: error => {
reject(error);
}
}
);
}
});
});
}
signout(): void {
if (this.currentUser) {
this.currentUser.signOut();
}
}
}
ユーザー属性の取得
ユーザーの属性値(Nameとか)を取得するにはgetUserAttributes
メソッドを実行する。
getCurrentUser
の戻り値であるCognitoUser
にあるメソッドだけど、そのまま実行すると401エラーになる。
getSession
でセッション情報を取っている中で属性値を取得する。
class CognitoAuthenticator {
/* 省略 */
getUserAttributes() {
return new Promise<CognitoUserAttribute[] | undefined>(
(resolve, reject) => {
const currentUser = this.currentUser;
if (currentUser) {
// eslint-disable-next-line
currentUser.getSession((error: Error | null, session: CognitoUserSession | null) => {
if (error) {
reject(error);
} else {
currentUser.getUserAttributes((error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
}
}
);
} else {
reject(new Error("no user"));
}
}
);
}
}
view
実際にCognitoAuthenticator
を使うところ。
サインインに成功した後、ユーザーの属性を取得してストアに保存する。
import { defineComponent, ref } from "vue";
import { cognitoAuthenticator } from "@/plugins/cognito-authenticator";
import { useRouter } from "vue-router";
import { useStore } from "vuex";
export default defineComponent({
name: "Signin",
setup() {
const userName = ref<string>("");
const password = ref<string>("");
const router = useRouter();
const store = useStore();
const signin = () => {
cognitoAuthenticator
.signin(userName.value, password.value)
.then(result => {
cognitoAuthenticator
.getUserAttributes()
.then(attrs => {
let username, displayName, email;
if (attrs) {
attrs.forEach(attr => {
switch (attr.getName()) {
case "sub":
username = attr.getValue();
break;
case "name":
displayName = attr.getValue();
break;
case "email":
email = attr.getValue();
break;
default:
break;
}
});
}
store.dispatch("setUser", {
idToken: result.getIdToken(),
accessToken: result.getAccessToken(),
refreshToken: result.getRefreshToken(),
displayName: displayName,
username: username,
email: email
});
router.push({ name: "AdminHome" });
})
.catch(error => {
console.log(error);
});
})
.catch(error => {
console.error(error);
});
};
return {
userName,
password,
signin
};
}
});
最後に
最近になってようやくAWSを自分で使い始めた。 仕事で使うようになったって言うのが大きいけどね。
すっごい便利だと思うし、色々できるんだろうけど、むつかしいなぁ...。