メンバーシッププロバイダーとか実装したくないですはい。ということで認証かけてないWebAPIを1個置いといて、その中で認証チケットの発行という感じかなあ。
Web.configでフォーム認証を有効かするためにsystem.webの下に以下の要素を追加
<authentication mode="Forms" />
こんな感じのクラスをクラスライブラリに定義しておいて…(ポータブルライブラリがいいかな)
using System.Runtime.Serialization; namespace AuthApiTest.Models { [DataContract] public class LoginParameter { [DataMember(Name = "loginId")] public string LoginId { get; set; } [DataMember(Name = "password")] public string Password { get; set; } } }
using System.Runtime.Serialization; namespace AuthApiTest.Models { [DataContract] public class LoginResult { [DataMember(Name = "userName")] public string UserName { get; set; } } }
こんな感じのWebAPIをおいとく。*1
using AuthApiTest.Models; using System.Net; using System.Web.Http; using System.Web.Security; namespace AuthApiTest.Controllers { public class AuthController : ApiController { public LoginResult Post(LoginParameter param) { if (param.LoginId == "user" && param.Password == "p@ssw0rd") { FormsAuthentication.SetAuthCookie("user", false); return new LoginResult { UserName = "田中" }; } // こういうとき、何番返すのが妥当なんだろうか throw new HttpResponseException(HttpStatusCode.BadRequest); } } }
認証かかったAPIとしてValuesControllerというのも作っておきます。
using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace AuthApiTest.Controllers { // 認証しないと呼べないよ~ [Authorize] public class ValuesController : ApiController { public IEnumerable<string> Get() { return Enumerable.Range(1, 10).Select(i => "value" + i); } } }
お膳立てはできたのでクライアント側です。今回はコンソールアプリケーションでいってみます。コンソールアプリケーションには、LoginParameterやLoginResultクラスを定義したライブラリを追加しておきます。あとは、HttpClientの最新のやつをNuGetからいれておきます。PostAsAsyncとかのAPIがあるとすごい楽なので。
- Microsoft.AspNet.WebApi.Client
あとは、ログインして呼び出してみる。こんな感じに書いてみました。ストアアプリもHttpClientのリリース前のバージョンだと、PostAsJsonAsyncとかあって便利。早く正式こないかなぁ。
using AuthApiTest.Models; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; namespace AuthApiTest.Client { class Program { static void Main(string[] args) { var cookie = new CookieContainer(); Console.WriteLine("-------"); { // 認証して通信 var client = Create(cookie); var response = client.PostAsJsonAsync("http://localhost:3502/api/auth", new LoginParameter { LoginId = "user", Password = "p@ssw0rd" }).Result; Console.WriteLine(response.Content.ReadAsAsync<LoginResult>().Result.UserName); var response2 = client.GetAsync("http://localhost:3502/api/values").Result; // 失敗してたら例外とばす response2.EnsureSuccessStatusCode(); Console.WriteLine(response2.Content .ReadAsAsync<IEnumerable<string>>() .Result .Aggregate((c, a) => c + ", " + a)); } Console.WriteLine("-------"); { // 認証してないと失敗する確認 var client = Create(new CookieContainer()); var response = client.GetAsync("http://localhost:3502/api/values").Result; try { // 失敗してたら例外とばす response.EnsureSuccessStatusCode(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } Console.WriteLine("-------"); { // cookie containerさえ共有してればおk // 認証して通信 var client = Create(cookie); var response = client.GetAsync("http://localhost:3502/api/values").Result; // 失敗してたら例外とばす response.EnsureSuccessStatusCode(); Console.WriteLine(response.Content .ReadAsAsync<IEnumerable<string>>() .Result .Aggregate((c, a) => c + ", " + a)); } } // HttpClient作るよ private static HttpClient Create(CookieContainer cookie) { return new HttpClient(new HttpClientHandler { CookieContainer = cookie }); } } }
実行結果は以下のようになります。
------- 田中 value1, value2, value3, value4, value5, value6, value7, value8, value9, value10 ------- Response status code does not indicate success: 401 (Unauthorized). ------- value1, value2, value3, value4, value5, value6, value7, value8, value9, value10
*1:パスワードは平文で保存しちゃだめよ