LINE Loginを利用したWebアプリを ASP.NET Core + OpenID Connectで実装する
■ 目次
チュートリアル
今回は、LINE Loginを利用したWebアプリケーションをASP.NET Core +OpenID Connectで実装する方法について解説したいと思います。
はじめに
ここでは、Visual Studio 2017を使って「「ASP.NET Core Webアプリケーション」テンプレートからLINE Loginに対応したWebアプリを実装する手順」について解説します。
なお、ASP.NET CoreでOpenID Connectを使用する手順は、こちらの記事を参考にさせていただきました。
また、この記事の解説に使用したサンプルアプリをGitHubに上げています。 とりあえず動かしてみたいという方はこちらをCloneして試してみてください。
※ このサンプルアプリを試す際は、以下の手順でLINE LoginのChannel情報等を設定してください。
LINE の設定
LINE Loginアカウントを作成する
まずは、以下の公式ドキュメントに従ってLINE Loginアカウントを作成します。
連携するBotアカウントの用意
ログイン時に友達追加するBotのアカウントも作成しておきます。プッシュメッセージを使用するのでDeveloper Trialプランで作成します。 (もちろん、すでに作成済みのBotアカウントで試しても良いです)
なお、今回はログイン時に友達追加できることと、Webアプリからプッシュメッセージが送信できることが確認できれば良いのでWebhookの設定は不要です。
LINE Login アカウントの設定
LINE Loginアカウントを作成したら「Channel基本設定」を確認します。
- Channel ID とChannel Secretは後で必要となるので控えておきます
- 「このチャネルにリンクされたボット」欄で、作成済みのBotの一覧から先ほど用意したBotを選択します
- 「アプリタイプ」にはWEBを選択します
左側のメニューで「アプリ設定」を選択し、ログイン後のリダイレクト先を設定します。
- リダイレクト先のパスは「/signin-oidc」とします。
- ローカルデバッグでの確認であれば、Visual Studio でのデバッグ実行時のURLでOKです。(デバッグ時のURLはPropertiesフォルダ内にある「launchSettings.json」で確認できます)
Webアプリケーションの作成
ASP.NET Coreのプロジェクトを作成する
メニュー[ファイル]-[新規作成]-[プロジェクト...]から「ASP.NET Core Webアプリケーション」を選択
テンプレートのタイプは「Webアプリケーション(モデル ビュー コントローラ)」を選択。「認証なし」のままで作成します。
NuGetパッケージを追加する
「ソリューションのNuGetパッケージの管理」画面または、パッケージマネージャコンソールで Microsoft.AspNetCore.Authentication.OpenIdConnect
をインストールします。
PM> Install-Package Microsoft.AspNetCore.Authentication.OpenIdConnect
AppSettings.json に LINE Login のChannel情報を設定する
予め、appsettings.json に LINE Login のアカウント登録時に取得した ChannelIdとChannel Secretの値を追加しておきます。
{ "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Warning" } }, "LineSettings": { "LoginClientId": "156xxxxxxxxxx", "LoginClientSecret": "934a4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", } }
StartupクラスでOpenID Connectを使用するように設定する
あとは、Stertup.cs で以下の記述を追加するだけでOKです。 (詳細は冒頭でリンクしたしばやん先生の記事をご確認ください)
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddMvc(); //OpenID Connectを使用するための記述 ここから==> services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddOpenIdConnect(o => { //ClientIdとClientSecretをConfiguration(appsettings.json)から取得。階層のあるデータはコロン(:)で区切って指定する o.ClientId = Configuration["LineSettings:LoginClientId"]; o.ClientSecret = Configuration["LineSettings:LoginClientSecret"]; o.ResponseType = OpenIdConnectResponseType.Code; o.UseTokenLifetime = true; o.SaveTokens = true; o.Configuration = new OpenIdConnectConfiguration { Issuer = "https://access.line.me", AuthorizationEndpoint = "https://access.line.me/oauth2/v2.1/authorize", TokenEndpoint = "https://api.line.me/oauth2/v2.1/token" }; o.TokenValidationParameters = new TokenValidationParameters { IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(o.ClientSecret)), NameClaimType = "name", ValidAudience = o.ClientId }; }); //<==ここまで } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseBrowserLink(); app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); //Authentication Middleware を使う app.UseAuthentication(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } }
これで、Controller の[Authorize]属性を付けたメソッドにアクセスすると、LINEアカウントのログイン画面にリダイレクトされるようになります。
・Controllers/HomeController.c
//<HomeController.cs> public class HomeController:Controller { [Authorize] public IActionResult Index() { return View(); } }
ログイン時にBotアカウントを友達追加できるようにする
ユーザーがLINEアカウントの認可画面で関連するBotを友達追加するか否かを選択できるようにするには、認可URLに、クエリパラメータbot_promptを追加します。
先ほどのコードのAddOpenIdConnect()
に渡すラムダ式内、AuthorizationEndpoint に設定するURLを以下の様に修正します。
o.Configuration = new OpenIdConnectConfiguration { Issuer = "https://access.line.me", AuthorizationEndpoint = "https://access.line.me/oauth2/v2.1/authorize?bot_prompt=normal", TokenEndpoint = "https://api.line.me/oauth2/v2.1/token" };
bot_prompt の値は、normal、aggressiveの2種類があり、aggressiveを設定した場合は、認可画面を閉じた後にボット追加用の確認画面が表示されるようになります。
- normal の場合 (認可画面内にボット追加確認用のチェックボックスが追加される)
- aggressive の場合(認可画面からログイン後、確認用のダイアログが表示される)
なお、「ブロック解除」と表示されているのは、動作確認用に一度友達追加したBOTを「ブロック」しているためです。初めて友達追加する場合は「友達追加」と表示されます。
取得したユーザー情報を確認する
デバッカで確認してみると、取得したユーザーの情報はUser.Identity.Claimes
に格納されているのが分かります。
ClaimsプロパティはKey-Valueのコレクションとなっていて、値はUser.FindFirst()
メソッドにKeyを指定して取得することができます。
定義済みのClaimは"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"の様にURLで指定する必要がありますが、 System.Security.Claims.ClaimTypes に定数として定義されているのでこれを使用します。
//View(Razor)でもControllerでも同じ様に取得できます var name =User.FindFirst("picture").Value; //ユーザー名はUser.Identity.Nameでも取得可 var picture = User.FindFirst("picture").Value; //画像のURLを取得 var userId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier).Value; //LINEアカウントに紐づくユーザーID
それでは、ログインしたユーザーの情報が確認できるように、トップページ(Home/Index)のViewを書き換えてみます。
<-- Index.cshtml --> @{ ViewData["Title"] = "Home Page"; } <div class="jumbotron"> <div class="panel panel-default center-block"> <div class="panel panel-heading"> <div class="row"> <div class="col-md-10 col-sm-10 col-xs-8"> <p><img src="@User.FindFirst("picture").Value" width="32" height="32" alt="User Image"> @User.Identity.Name</p> </div> <div class="col-md-2 col-sm-2 col-xs-4"> <a class="btn btn-default" role="button" asp-area="" asp-controller="Account" asp-action="Logout">Logout</a> </div> </div> </div> </div> </div>
ついでに「Logout」ボタンでログアウトできるように、AccountControllerを追加してLogout()メソッドを実装します。
//<AccountController.cs> using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Mvc; namespace LineLoginSampleApp.Controllers { public class AccountController : Controller { public IActionResult Logout() { return SignOut(new AuthenticationProperties { RedirectUri = "/" }, CookieAuthenticationDefaults.AuthenticationScheme); } } }
ここで、一度デバッグ実行してみましょう。
LINEのログイン画面からログイン後、以下の様にユーザー名と画像が表示されればOKです。
「Logout」ボタンも確認してみましょう。ボタン押下後、再びLINEのログイン画面にリダイレクトされることが確認できると思います。
Botからプッシュメッセージを送ってみる
次は、LINEログイン時にBotを友達追加したユーザーに対してBotからプッシュメッセージを送ってみましょう。
Messaging APIのライブラリを追加
LINE Messaging API のSDKをNuGetからインストールします。
PM > Install-Package Line.Messaging
appSettings.jsonにBotのChannel アクセストークンを追加する
LINE Developersコンソールを開き、今回用意したBotを選択します。
Channel基本設定で「アクセストークン(ロングターム)」を確認し、appSettings.jsonに追加します。
{ "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Warning" } }, "LineSettings": { "LoginClientId": "156xxxxxxxxxx", "LoginClientSecret": "934a4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "MessagingAccessToken": "zd1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } }
メッセージを送ってみる
画面から送信するメッセージの内容を設定して送れるようにViewとControllerを書き換えます。
・Home/Index.cshtml に、メッセージの入力ボックスと送信ボタンを追加します。
<-- Index.cshtml --> @{ ViewData["Title"] = "Home Page"; } @using System.Security.Claims; <div class="jumbotron"> <div class="panel panel-default center-block"> <div class="panel panel-heading"> <div class="row"> <div class="col-md-10 col-sm-10 col-xs-8"> <p> <img src="@User.FindFirst("picture")?.Value" width="32" height="32" alt="User Image" /> @User.Identity.Name </p> </div> <div class="col-md-2 col-sm-2 col-xs-4"> <a class="btn btn-default" role="button" asp-area="" asp-controller="Account" asp-action="Logout">Logout</a> </div> </div> </div> <div class="panel panel-body"> <h2>プッシュメッセージ送信テスト</h2> <form role="form" asp-area="" asp-controller="Home" asp-action="PushMessage" method="post"> <input type="text" name="pushMessage" class="form-control" placeholder="プッシュするメッセージを入力してください"> <button type="submit" class="btn btn-default">送信</button> </form> </div> </div> </div>
・Views/Home/ の配下にメッセージ送信後の遷移先となるView(PushMessage.cshtml)を作成しておきます。
<-- PushMessage.cshtml --> @{ ViewData["Title"] = "PushMessage"; } <h2>送信しました</h2> <a class="btn btn-default" role="button" asp-area="" asp-controller="Home" asp-action="Index">戻る</a>
・HomeControllerにPushMessageメソッドを追加してそこに送信処理を記述します。
//<HomeController.cs> public class HomeController : Controller { private LineSettings lineSettings; public HomeController(IOptions<LineSettings> options) { lineSettings = options.Value; } [Authorize] public IActionResult Index() { return View(); } [HttpPost] [Authorize] public async Task<IActionResult> PushMessage(string pushMessage) { var userId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier).Value; using (var line = new Line.Messaging.LineMessagingClient(lineSettings.MessagingAccessToken)) { await line.PushMessageAsync(userId, pushMessage); } return View(); } }
なお、appSettings.jsonに設定したアクセストークンを、HomeControllerのコンストラクタの引数LineSettings
オブジェクトから取得していますが、これを行うためにはStartupクラスでアプリケーション設定をDI(Dependency Injection)するよう設定しておく必要があります。
・ModelsディレクトリにLineSettingsクラスを追加します。
//<LineSettings.cs> using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace LineLoginSampleApp.Models { public class LineSettings { public string LoginClientId { get; set; } public string LoginClientSecret { get; set; } public string MessagingAccessToken { get; set; } } }
・StartupクラスのConfigurationServices()メソッドに、アプリケーション設定をDIするコードを追加します。
//<Stertup.cs> public void ConfigureServices(IServiceCollection services) { services.AddMvc(); //ConfigurationからLineSettingsセクションを抽出してDependency Injectionする services.Configure<LineSettings>(Configuration.GetSection("LineSettings")); //... }
これで準備完了です。実行してみましょう。
・メッセージを入力して「送信」
・LINEアプリを確認し、BOTから入力したメッセージが送られてきていれば成功です!
次は
次は、ユーザーのメールアドレスを取得する方法を見てみようと思いますが、長くなりすぎてしまったので次回にします。