はじめに
本記事はPERSOL PROCESS & TECHNOLOGY Advent Calendar 2023の記事です。
業務でLINEとAWS実装を経験することがあり、独学ながら実装したお話を書いてみようと思います。といってもLINEの公式ドキュメントがすごく丁寧に教えてくれているので、こんなふうに実装できるんだ〜便利〜とか思ってくれれば良きです。では
背景
今回日本で利用者数が多いSNSであるLINEと、サーバーレスであるAWS Lambdaを利用しています。
LINEは、月間ユーザー数9,500万人(2023年6月末時点)と多くのユーザー数を抱えています。
参照:LINEユーザー層
ともあり、年齢層に関係なく利用ユーザーも多いです。(個人的には思ったより高齢層というのも関係なく高いのに驚き)使いやすくて便利。ですね。
Lambdaはサーバーレスのサービスのため、サーバー運用について考える必要がなく、簡単に実装できます。こちらも使いやすくて便利。です。
ユーザーも使いやすい。(使われやすいともいう。)開発者も開発しやすい。のでこのような構成を選択しています。
構成図
今回はどこかのサイトのユーザーが自環境へ入り、LINEログインのリダイレクトを行います。リダイレクト結果が自環境に戻り、結果をどこかのサイトへ結果を返す、というような処理を実装します。
(今回の事象では認証前後で、Lambda関数による処理が必要なためこのような構成としています。LINE認証を行うのに必ずLamdba関数を通す必要はありません。)
ユーザー視点遷移
ユーザーはどこかのサイトの”LINEID連携”ボタンを押下すると、紐づいている公式LINEアカウントへアクセス権限を"許可する"ボタンを押下、無事にユーザー情報を取得できれば完了!となります。
(ユーザーのLINEアカウントと分けるため本記事では認証されるLINEアカウントを”公式アカウント”と呼んでいます。)
では実際の実装内容に入ります。
事前準備
必要なものは
・LINEDevelopersアカウント
・AWSアカウント
となります。
登録方法は今回省略します。どちらもぽちぽちと簡単に作成できます。
LINE DevelopersではLINE公式チャネルを作成します。
どのアカウントへログインするのかなどを特定するID情報が実装時必要となります。呼び出し時は上記”開発中”→”公開済み”に変更するのを忘れずに!
AWSではLambda関数、APIGatewayを作成します。(権限や設定値等は各自の設計および環境に依存するため、参考程度にお考えください。)
作業環境によって1から作成しても、コンテナイメージから作成してどちらでも大丈夫です。
(後日本開発環境のCI/CDに関する記事を投稿予定です→PERSOL PROCESS & TECHNOLOGY Advent Calendar 2023)
次にAPIGatewayです。
今回はREST APIを選択しています。
作成したREST APIにリソースを作成して、その中にメソッドを作成します。ここでは先ほど作成したLambda関数と統合したメソッドとなります。
また今回はLambdaプロキシ統合を利用しています。簡単に言えば、リクエストやレスポンスなどAPIGatewayでマッピングしなくても簡単に使えるよ〜というやつです。
作成したAPIはこんな感じです。1つめのAPIのメソッドタイプはGETでもPOSTでもこのAPIを呼び出す先に合わせ選択ください。2つめのAPIメソッドタイプはLINEからのリダイレクトを受信する箇所になるため、"GET"とします。
AWS Lambda実装
1つ目のLamdba関数
1つ目のLambda関数ではAPIを受けてLINEの認可URLを作成し、ユーザーに向けてリダイレクトを実施します。
LINE認可は、LINEとユーザー間で認証と認可のプロセスを行います。
ここでの検討ポイントは”どんなユーザー情報が欲しいのか”ということです。
認可URLのパラメータ”scope”で、どのアクセス権が欲しいのかを指定します。
scope = profile → プロフィール情報(LINEユーザーID、LINE表示名前、LINEアイコンURLなど)
scope = openid → ユーザー識別子(LINEユーザーID、IDトークンの有効期間など)
scope = email → メールアドレス
メールアドレスへのアクセス権が必要な場合は別途LINEDevelopersページよりLINE公式アカウントのメールアドレス取得権限の申請が必要です。
その他必要情報は
・LINEログインチャネルのチャネルID→LINEDevelopersページより、公式アカウントのチャネル基本情報に記載あり。
・リダイレクトURL→AWS APIGatewayページより、デプロイしたAPIのステージ詳細に記載あり。
このリダイレクトURLはLINEDevelopersページ上で設定したコールバックURLと同じURLとなります。合わせて設定します。
今回リダイレクトを実施するため、レスポンスのstatuscodeは"302"、headersはリダイレクトURLを付与します。
参考ソースコード↓
import json
import os
def lambda_handler(event, context):
# ステート生成
state = hashlib.sha256(os.urandom(32)).hexdigest()
# 環境値(ご自身の環境値に置き換えてください。)
redirect_uri = 'REDIRECT_URL'
client_id = 'LINE_CHANNEL_ID'
base_url = "https://access.line.me/oauth2/v2.1/authorize"
params = {
"response_type": "code",
"client_id": client_id,
"redirect_uri": redirect_uri,
"state": state,
"scope": "profile"
}
full_url = f"{base_url}?{'&'.join([f'{key}={value}' for key, value in params.items()])}"
response = {
'statusCode': 302,
'headers': {
'Location': full_url
}
}
return response
2つ目のLambda関数
2つ目のLambda関数では、LINE認可したユーザー情報を取得し、完了した旨を返します。
完了すると、パラメータ"code"、"state"含みリダイレクトされます。
"code"パラメータをもとに、アクセストークンを取得します。
scope=profileの場合、このアクセストークンからLINEユーザーIDやLINE表示名を取得することも可能です(今回は対象外)
もしユーザーが認可しなかった場合、パラメーター"error"、"error_description"となります。されなかった場合の処理を別途考慮する必要があります。今回の実装ではエラーとして処理しています。
参考ソースコード
import json
import os
import urllib
def lambda_handler(event, context):
#リクエスト情報取得
parameters = event.get('queryStringParameters')
#LINEエラーの場合は処理を終了する
if 'error' in parameters:
return {
'statusCode': parameters['error'],
'body': json.dumps({'message': parameters['error_description']}, ensure_ascii=False)
}
#リクエスト情報取得
code = parameters['code']
state = parameters['state']
# 環境値(ご自身の環境値に置き換えてください。)
redirect_uri = 'REDIRECT_URL'
client_id = 'LINE_CHANNEL_ID'
client_secret = 'LINE_CHANNEL_SEACRET'
# LINE Messaging APIのエンドポイント
line_api_endpoint_token = 'https://api.line.me/oauth2/v2.1/token'
# LINEへアクセストークン取得リクエスト送信
# リクエストヘッダー
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
# LINE APIの認証情報
data = urllib.parse.urlencode({
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': redirect_uri,
'client_id': client_id,
'client_secret': client_secret
}).encode('utf-8')
try:
# HTTP POSTリクエストの送信
request = urllib.request.Request(line_api_endpoint_token, data=data, headers=headers, method='POST')
with urllib.request.urlopen(request, data=data) as f:
response = f.read()
line_info = json.loads(response)
access_token = line_info['access_token']
return {
'statusCode': 200,
'body': {
'message': access_token
}
}
except Exception as e:
# エラーハンドリング
error_message = e.read().decode("utf-8")
return {
'statusCode': e.code,
'body': {
'message': error_message
}
}
return response
まとめ
今回は公式LINEアカウントのログイン認証行い、認可したユーザーのLINEユーザー情報を取得することができました。今回Lambda関数ではログイン処理しか行っていませんが、実際の実装では取得したユーザー情報をDB保存したりと他の処理を組み合わせて実装することが可能です。ウェブアプリにLINEログインをAWSで実装する際の参考になればと思います。
自身にとってAWSとLINE機能、両方において技術の理解を深めることができました。また後日、本開発環境のCI/CDに関する記事を投稿予定です。そちらもぜひ→PERSOL PROCESS & TECHNOLOGY Advent Calendar 2023