MVCアプリケーションでiCalendarファイル(.ics)を提供しようとしています。
これまでのところ、正常に動作しています。カレンダーのURLをサブスクライブしているiPhoneを持っていますが、今度は各ユーザーにパーソナライズされたカレンダーを提供する必要があります。
iPhoneでカレンダーを購読するときに、ユーザー名とパスワードを入力できますが、MVCアプリでこれらにアクセスする方法がわかりません。
認証の仕組みと実装方法の詳細はどこにありますか?
MVCアプリケーションでiCalendarファイル(.ics)を提供しようとしています。
これまでのところ、正常に動作しています。カレンダーのURLをサブスクライブしているiPhoneを持っていますが、今度は各ユーザーにパーソナライズされたカレンダーを提供する必要があります。
iPhoneでカレンダーを購読するときに、ユーザー名とパスワードを入力できますが、MVCアプリでこれらにアクセスする方法がわかりません。
認証の仕組みと実装方法の詳細はどこにありますか?
必要なのは基本認証であることがわかります。半分は機能していましたが、IIS構成が邪魔になりました。したがって、Authorizationヘッダーがないときに401応答を返すだけで、クライアント(iPhoneなど)はカレンダーをサブスクライブするためにユーザー名/パスワードを要求します。
Authorizationリクエストヘッダーがあるリクエストの承認時に、基本認証を処理して、base64でエンコードされた文字列からユーザー名とパスワードを取得できます。
MVCの便利なコードは次のとおりです。
public class BasicAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
var auth = filterContext.HttpContext.Request.Headers["Authorization"];
if (!String.IsNullOrEmpty(auth))
{
var encodedDataAsBytes = Convert.FromBase64String(auth.Replace("Basic ", ""));
var value = Encoding.ASCII.GetString(encodedDataAsBytes);
var username = value.Substring(0, value.IndexOf(':'));
var password = value.Substring(value.IndexOf(':') + 1);
if (MembershipService.ValidateUser(username, password))
{
filterContext.HttpContext.User = new GenericPrincipal(new GenericIdentity(username), null);
}
else
{
filterContext.Result = new HttpStatusCodeResult(401);
}
}
else
{
if (AuthorizeCore(filterContext.HttpContext))
{
var cachePolicy = filterContext.HttpContext.Response.Cache;
cachePolicy.SetProxyMaxAge(new TimeSpan(0));
cachePolicy.AddValidationCallback(CacheValidateHandler, null);
}
else
{
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusDescription = "Unauthorized";
filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", "Basic realm=\"Secure Calendar\"");
filterContext.HttpContext.Response.Write("401, please authenticate");
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.Result = new EmptyResult();
filterContext.HttpContext.Response.End();
}
}
}
private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
{
validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
}
}
次に、私のコントローラーアクションは次のようになります。
[BasicAuthorize]
public ActionResult Calendar()
{
var userName = HttpContext.User.Identity.Name;
var appointments = GetAppointments(userName);
return new CalendarResult(appointments, "Appointments.ics");
}
これは本当に役に立ちましたが、開発中にいくつかの問題が発生し、他の人を救うためにそれらのいくつかを共有したいと思いました。
私は自分のWebアプリケーションからAndroidデバイスのカレンダーにデータを取得しようとしていて、ホスティングサービスとしてdiscountaspを使用していました。
私が最初に遭遇した問題は、サーバーにアップロードしたときに検証が機能しなかったことでした。それは、discountaspのコントロールパネルログインを受け入れていましたが、フォームログインは受け入れていませんでした。
これに対する答えは、IISマネージャーで基本認証をオフにすることでした。これで問題は解決しました。
次に、カレンダーをAndroidデバイスに同期するために使用したアプリはiCalSync2と呼ばれていました。これは素晴らしいアプリであり、うまく機能します。しかし、ファイルが.icsとして配信された場合にのみ適切に機能することがわかりました(何らかの理由で.icalとして配置しました..遅れている必要があります)。また、webcalオプションを選択する必要がありました。
最後に、URLの先頭にhttp://ではなくwebcal://を追加する必要があることがわかりました。
また、上記のコードはロール入力変数を無視し、常に何も渡さないため、カレンダールーチン内でロールベースのチェックを実行するか、ロール変数を処理するために上記のコードを変更する必要がある場合があるので注意してください。