LINEログインしてプロフィール取るところまでできたので忘れないように書いておく。
LINEログインをして、ユーザのuserid、表示名、プロフィール画像を取得して、表示名と画像を表示するところまで。
Perl で Mojolicious::lite でheroku にデプロイしている。
もろもろチェックやなんやらは省略している。
実質のファイルは
- myapp.pl
- templates/index.html.ep
- templates/layouts/default.html.ep
- cpanfile
requires 'Mojolicious';
requires 'IO::Socket::SSL', '>=2.009';
- app.psgi (空っぽ)
- Procfile
web: starman --preload-app --port $PORT myapp.pl psgi
プロフィールをとるまでは、こんな感じ。
ログイン認証させるURLにはいくつかパラメータの指定が必要。 そのうち state は正しいアクセスかどうかを確認するのに使う。 ログイン認証するURLに含めたstateの値と、ログイン後に返ってくるstateの値が一致することを、こっちのアプリ側で検証してやらないといけない。もちろんアクセスごとにランダムな値を設定しないといけない。
これって要するにMojoliciousのcsrf_tokenを使えばいいんじゃねということで使った。
ログインボタンのURLに含めるstate=にはcsrf_tokenを入れる。
csrf_tokenの検証は、普通なら元からあるメソッドでできるが、今回は直に、返ってきたstateの値とこっちのcsrf_tokenの値を比較した。
#!/usr/bin/env perl use lib './lib'; use lib './local/lib/perl5'; use Mojolicious::Lite; use Mojo::UserAgent; helper is_ok_csrf_token => sub { my $self = shift; my $csrf_token = $self->session->{csrf_token}; my $state = $self->param('state'); # csrf_token return 1 if $csrf_token eq $state; return; }; helper get => sub { my ($self, $arg) = @_; my $url = $arg->{'url'}; my $header = $arg->{'header'}; my $ua = Mojo::UserAgent->new(); my $tx = $ua->get($url => $header); if ( my $res = $tx->success ) { return $res->json; } }; helper post => sub { my ($self, $arg) = @_; my $url = $arg->{'url'}; my $param = $arg->{'param'}; my $ua = Mojo::UserAgent->new(); my $tx = $ua->post($url => form => $param); if ( my $res = $tx->success ) { return = $res->json; } }; helper get_profile => sub { my $self = shift; my $access_token = $self->get_access_token; my $param = {Authorization => "Bearer $access_token"}; my $url = 'https://api.line.me/v2/profile'; my $result_hash = $self->get({ url => $url, header => $param, }) or return; return $result_hash; }; helper get_profile => sub { my $self = shift; my $access_token = $self->get_access_token; my $param = {Authorization => "Bearer $access_token"}; my $url = 'https://api.line.me/v2/profile'; my $result_hash = $self->get({ url => $url, header => $param, }) or return; return $result_hash; }; helper get_access_token => sub { my $self = shift; my $code = $self->param('code'); my $token_url = 'https://api.line.me/oauth2/v2.1/token'; my $post_param = { grant_type => 'authorization_code', code => $code, redirect_uri => $ENV{CALL_BACK_URL}, client_id => $ENV{CHANNEL_ID}, client_secret => $ENV{CHANNEL_SECRET}, }; my $result_hash = $self->post({ url => $token_url, param => $post_param, }) or return; my $access_token = $result_hash->{'access_token'}; return $access_token if $access_token; return; }; get '/' => sub { my $c = shift; if ( $c->param('code') && $c->is_ok_csrf_token ) { my $profile_hash = $c->get_profile; $c->stash('profile_hash' => $profile_hash); } $c->render(template => 'index'); }; app->secrets([$ENV{MOJO_SECRETS}]) if defined $ENV{MOJO_SECRETS}; app->start;
% layout 'default'; % title 'Welcome'; % my $profile_hash = stash('profile_hash'); <h1>LINE ログインテスト</h1> <div> <a href="https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=<%= $ENV{CHANNEL_ID} %>&redirect_uri=<%= $ENV{CALL_BACK_URL} %>&state=<%= csrf_token %>&scope=profile"> LINEでログインする </a> </div> <div> printデバッグ用<%= stash('message') %> </div> <% if ($profile_hash) { %> <div> <p><%= $profile_hash->{'displayName'} %></p> <img src="<%= $profile_hash->{'pictureUrl'} %>"> </div> <% } %>