Closed mugihouse closed 1 year ago
時々起きるだと原因の特定が難しいのでまずはエラーを再現出来るようにするのが良いかと思います。
binding.pryやputsなどを使ってどんなときにline_id = JSON.parse(res.body)['sub']
の値がnilになってしまうのかを検証してみたり、いろんな挙動を試してみてエラーの原因を探ってみるのが良さそうです
puts で確認しました。 users#createメソッドのid_token,channel_idまでは取得できていました。
res = Net::HTTP.post_form(URI.parse('https://api.line.me/oauth2/v2.1/verify'), { 'id_token' => id_token, 'client_id' => channel_id })
p res
p res.body
と記述したところ、
#<Net::HTTPBadRequest 400 Bad Request readbody=true>
"{\"error\":\"invalid_request\",\"error_description\":\"IdToken expired.\"}"
と返ってきたため、ここでresを取得できていなかったようです。
対応策として以下のサイトのLIFF SDKがIDトークンを取得するタイミングの部分がうまくいっていない原因だと考えていますが、javascript上での再現方法がわからず止まっています。 以下のように変更しましたが、結果は同じままでした。 https://developers.line.biz/ja/reference/liff/#get-id-token
document.addEventListener('DOMContentLoaded', () => {
//csrf-token取得
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
// LIFFのメソッドを実行できるようにする
liff
.init({
liffId: gon.liff_id,
withLoginOnExternalBrowser: true
})
// 初期化後の処理設定
liff
.ready.then(() => {
if (!liff.isLoggedIn()) {
liff.login()
liff
.init({
liffId: gon.liff_id, // Use own liffId
})
.then(() => {
const idToken = liff.getIDToken();
console.log(idToken); // print raw idToken object
});
} else {
const idToken = liff.getIDToken()
const body = `idToken=${idToken}`
const request = new Request('/users', {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
'X-CSRF-Token': token
},
method: 'POST',
body: body
})
fetch(request)
.then(response => response.json())
.then(data => {
data_id = data
})
.then(() => {
window.location = '/after_login'
})
}
})
})
これとか関係ありそうですかね? https://zenn.dev/arahabica/articles/274bb147a91d8a
コメントありがとうございます。 いただいた資料を参考にコード作成して、最終的に以下のコードでログインできるようになりました! 念の為不備がないかご確認お願いします。
document.addEventListener('DOMContentLoaded', () => {
//csrf-token取得
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
const liffId = gon.liff_id
// liff関連のlocalStorageのキーのリストを取得
const getLiffLocalStorageKeys = (prefix) => {
const keys = []
for (var i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i)
if (key.indexOf(prefix) === 0) {
keys.push(key)
}
}
return keys
}
// 期限切れのIDTokenをクリアする
const clearExpiredIdToken = (liffId) => {
const keyPrefix = `LIFF_STORE:${liffId}:`
const key = keyPrefix + 'decodedIDToken'
const decodedIDTokenString = localStorage.getItem(key)
if (!decodedIDTokenString) {
return
}
const decodedIDToken = JSON.parse(decodedIDTokenString)
// 有効期限をチェック
if (new Date().getTime() > decodedIDToken.exp * 1000) {
const keys = getLiffLocalStorageKeys(keyPrefix)
keys.forEach(function (key) {
localStorage.removeItem(key)
})
}
}
const main = async (liffId) => {
clearExpiredIdToken(liffId)
// LIFFのメソッドを実行できるようにする
liff
.init({
liffId: liffId,
withLoginOnExternalBrowser: true
})
// 初期化後の処理設定
liff
.ready.then(() => {
if (!liff.isLoggedIn()) {
liff.login();
} else {
const idToken = liff.getIDToken()
const body = `idToken=${idToken}`
const request = new Request('/users', {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
'X-CSRF-Token': token
},
method: 'POST',
body: body
})
fetch(request)
.then(response => response.json())
.then(data => {
data_id = data
})
.then(() => {
window.location = '/after_login'
})
}
})
}
main(liffId)
});
おめです! 動いていればそれでLGTMです!
LINEログインを使ったPFを作成中です。 ログイン自体はできるのですが、突然current_userがnilになる現象が時々見られます。 特にログアウトを長時間行っているとログインできないことがあります。 この現象はcookieをリセットするとログインできるようになるため、そこに原因があると考えていますがまだ対処しきれていないので、アドバイスがあればご教授いただけると幸いです。
行った対処法
原因として考えられること
ログを見るとline_idがnilのuserを探しているため、line_idを取得できていないと考えています。
エラー発生時のログ
エラー画面