DEVELOPMENT
web
js
aws
cognito
amplify
vue
目次
AmplifyのAuth(Cognito)を使い、Vue−cliのプロジェクトで、Line(OIDC)アカウントでログインをしたい場合の設定方法と実装の仕方です。
AmplifyでLINEのログインのドキュメントが皆無でしたが、他のを参考にしつつ、ダメ元やりましたが、しっかり実装できましたので、ご紹介します。
AWS AmplifyのAuthをLine でログインする
前提
- Amplifyの導入済み
- Vue-cliでprojを開始しwelecomeページが表示されている
- ※注意 LineからEmailを取得するには、申請が必要です。そのため今回はCognito側の設定でEmailを必須にしない設定で進めます
- 参考 ▶ Line Developer
最初に
- AmplifyでAuthをadd済みの場合、Cognitoのユーザーの登録内容の必須項目等の編集がCognitoの仕様で不可なので、一回削除します。
$ amplify remove auth
$ rm ./aws-exports.js
$ amplify push
Amplify でAuthを追加する
$ amplify add auth
Using service: Cognito, provided by: awscloudformation
Do you want to use the default authentication and security configuration? (Use arrow keys)
❯ Default configuration <-これ
Default configuration with Social Provider (Federation)
Manual configuration
I want to learn more.
Do you want to use the default authentication and security configuration? Default configuration
How do you want users to be able to sign in? (Use arrow keys)
❯ Username <-これ
Email
Phone Number
Email and Phone Number
I want to learn more.
Do you want to use the default authentication and security configuration? Default configuration
How do you want users to be able to sign in? Username
Do you want to configure advanced settings?
No, I am done.
❯ Yes, I want to make some additional changes. <-これ
- Emailではなくて、Nameにする ※Emailのカーソルで、一回spaceキー、Nameでspaceキーを押す
◯ Gender (This attribute is not supported by Login With Amazon.)
◯ Locale (This attribute is not supported by Facebook, Google.)
◯ Given Name (This attribute is not supported by Login With Amazon.)
❯◯ Name
◯ Nickname (This attribute is not supported by Facebook, Google, Login With Amazon.)
◯ Phone Number (This attribute is not supported by Facebook, Login With Amazon.)
◯ Preferred Username (This attribute is not supported by Facebook, Google, Login With Amazon.)
- これは何も選択しない
Do you want to enable any of the following capabilities?
※間違えたら一回Control+Cで抜けてやり直せる
- pushして反映する
$ amplify push
Cotnitoのdomainを設定しておく
- AWS Consoleから、Cognito,ユーザープールで、amplifyから作成されたユーザープールの設定画面に
- メニューより、ドメイン名を選択し登録する(何でもよい)
Line Developer設定
- ログイン後
- プロバイダ作成
- Line Loginを選択して、チャンネル作成
- 登録後、上のタブメニューの「アプリ設定」
- コールバックURLは先程、設定したCognitoのドメインに下記のPathで設定する
https://先程設定したドメイン/oauth2/idpresponse
- ※ ここのPATHは指定されたものです。ドメインのみ可変です
- 参考 ▶ AWS Cognito
CognitoにLineプロバイダを登録
- Congito ユーザープール、メニューのIDプロバイダーを選択
- OpenID Connectを選択
- 各項目を設定する
- 発行者を入力したら、検出されないが「検出の実行」を押して表示された残りの項目にも下記を入力
項目 | 内容 |
---|---|
プロバイダ名 | LINE |
クライアントID | LineのチャンネルID |
クライアントのシークレット(オプション) | Lineのチャネルシークレット |
属性のリクエストメソッド | GET |
承認スコープ | profile mail openid |
発行者 | https://access.line.me |
識別子 (オプション) | なし |
認証エンドポイント | https://access.line.me/oauth2/v2.1/authorize |
トークンエンドポイント | https://api.line.me/oauth2/v2.1/token |
ユーザー情報エンドポイント | https://api.line.me/v2/profile |
Jwks uri | https://api.line.me/oauth2/v2.1/verify |
- 各エンドポイントはLine Deveoper Documentに
Lineログインに属性をマッピング
-
OIDCの追加から
- OIDC 属性: email と sub追加
- ユーザープール属性: email -> Emailと sub -> Name
アプリクライアントにIDプロバイダを設定する
- Cognitoページの「アプリクライアント」
-
アプリクライアントが2つあるので両方に設定します
- ****appclientWeb
- ****appclient
- 有効な ID プロバイダのLINEにチェック
-
コールバック URL(local時、状況により変えて下さい)
- コールバック URL: http://localhost:8080/login/
- サインアウト URL: http://localhost:8080/
- 許可されている OAuth フロー: Authorization code grantにチェック
- 許可されている OAuth スコープは全部チェック
- ※ 指定のURLには最後にスラッシュを忘れずに!
vue material ui を入れて置く
- 注意:見た目を整える(ボタンやローティングなど)のに、とりあえず使いました。他のframework使うならここはスキップして下さい
- インストール
$ yarn add vue-material
- プロジェクトに反映
~
import VueMaterial from 'vue-material'
import 'vue-material/dist/vue-material.min.css'
import 'vue-material/dist/theme/default.css' <-これ入れないと色つかない
Vue.use(VueMaterial)
import App from './App.vue'
~
Vueのコード
- 必要なパッケージを入れる
$ yarn add aws-amplify-vue vue-router vuex
- dir構造
- /
|- src/
|-- assets
|-- components
|-- views
|-- Login.vue(ラインのログインボタンのページ)<- 追加
|-- Top.vue(ログイン後のページ) <- 追加
|-- App.vue
|-- aws-exports.js <- 自動で追加
|-- aws-oauth-config.js <- 追加
|-- main.js
|-- router.js <- 追加
|-- sotre.js <- 追加
不足のファイルやDirは作成しておく
- aws-oauth-config.js
const oauth = {
domain: 'xxxxxxxxxxxxx.auth.xx-xxxx-x.amazoncognito.com',
scope: ['profile', 'email', 'openid', 'aws.cognito.signin.user.admin'],
redirectSignIn: 'http://localhost:8080/login/',
redirectSignOut: 'http://localhost:8080/',
responseType: 'code' // or 'token', note that REFRESH token will only be generated when the responseType is code
}
export default oauth
- App.vue
<template>
<div id="app">
<router-view /> <-- ルーター
</div>
</template>
<script>
export default {
name: 'app',
methods: {
}
}
</script>
<style>
#app {
}
</style>
- views/Login.vue
<template>
<div class="login">
<!--ログインコンポーネント-->
<md-button v-if="signined === false && loading === false" class="md-raised" v-on:click="signIn">Sign in LINE</md-button>
<md-progress-spinner v-if="loading" :md-diameter="30" :md-stroke="3" md-mode="indeterminate"></md-progress-spinner>
<p v-if="signined">Sign in しました。</p>
</div>
</template>
<script>
import router from '../router.js'
import Amplify, { Auth, Hub } from 'aws-amplify'
import awsconfig from '../aws-exports'
Amplify.configure(awsconfig)
import oauth from '../aws-oauth-config'
Auth.configure({ oauth })
export default {
name: 'login',
data () {
return {
signined: false,
loading: false,
}
},
created: function () {
Hub.listen('auth', (data) => {
this.loading = false
switch (data.payload.event) {
case 'signIn':
this.signined = true
router.push({path: '/'})
break
case 'signIn_failure':
break
default:
break
}
})
},
methods: {
signIn: async function() {
this.loading = true
let res = await Auth.federatedSignIn({provider: 'LINE'})
console.log(res)
}
}
}
</script>
- views/Top.vue
<template>
<div>
Top
トップページです
<amplify-sign-out></amplify-sign-out>
</div>
</template>
<script>
export default {
name: 'Top'
}
</script>
<style>
</style>
- main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router.js'
import store from './store.js'
Vue.config.productionTip = false
new Vue({
store,
router,
render: h => h(App),
}).$mount('#app')
- route.js
import Vue from 'vue'
import Router from 'vue-router'
import Top from './views/Top.vue'
import Login from './views/Login.vue'
import store from './store.js'
// Amplify読み込み
import { AmplifyEventBus, AmplifyPlugin } from 'aws-amplify-vue'
import * as AmplifyModules from 'aws-amplify'
Vue.use(Router)
Vue.use(AmplifyPlugin, AmplifyModules)
let user;
// ユーザー管理
getUser().then((user) => {
if (user) {
router.push({path: '/'});
}
})
function getUser() {
return Vue.prototype.$Amplify.Auth.currentAuthenticatedUser().then((data) => {
if (data && data.signInUserSession) {
store.commit('setUser', data);
return data;
}
}).catch(() => {
store.commit('setUser', null);
return null;
})
}
// ログイン状態管理
AmplifyEventBus.$on('authState', async (state) => {
if (state === 'signedOut'){
user = null;
store.commit('setUser', null);
router.push({path: '/login'});
}
else if (state === 'signedIn') {
user = await getUser();
router.push({path: '/'});
}
})
// ルーティング設定
const router = new Router({
mode: 'history',
routes: [
{
// ログインページ
path: '/login',
name: 'login',
component: Login
},
{
// トップページ
path: '/',
name: 'top',
component: Top,
meta: { requiresAuth: true}
}
]
})
// リダイレクト設定
router.beforeResolve(async (to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
user = await getUser();
if (!user) {
return next({
path: '/login'
})
}
return next()
}
return next()
})
export default router
- store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
user: null
},
mutations: {
// ユーザー情報保存
setUser(state, user) {
state.user = user
},
},
actions: {
},
modules: {
}
})
ハマったところ
-
Callbackを最初違うURLにし、違うページを用意していましたが、返ってきたときに、下記のエラーが出てうまくいきませんでした。リフレッシュをすればいいのかもしれませんが、手っ取り早く、リクエストしたページと同じページ(/login)で受け取るようにしたら上手くいきました
- invalidrequest_
- invalidgrant_
- 参考 ▶ AWS Cognito endpoint
- Amplify からOIDCの設定を自動で行うことは不可能なので、AWS コンソールからamplifyで自動作成されたユーザープールに設定を追加していく形でしたが、amplify側で認識してくれたのでなんとか実装できました。
まとめ
Amplifyでの、OIDC(Line)の実装サンプルがほとんどなく、ダメ元でトライしましたが、うまくいきました。
参考
⬇🙏よかったらシェアお願いします🙏⬇
Nobuyuki Ukai
株式会社UKAI 代表取締役CEO。建築を専攻していたが、新卒でYahoo!Japanにエンジニアとして入社。その後、転職、脱サラ、フリーランスエンジニアを経て、田舎へ移住し、ゲストハウスの開業、法人成り。ゲストハウス2軒、焼肉店、カフェ、食品製造業を運営しています。詳細はこちらから