[解決済み] OWINセキュリティ - OAuth2 Refreshトークンの実装方法
質問
Visual Studio 2013に付属するWeb API 2のテンプレートを使っているのですが、OWINミドルウェアでユーザー認証などを行っています。
このテンプレートでは
OAuthAuthorizationServerOptions
OAuth2 サーバーが 14 日で期限切れになるトークンを配布するように設定されていることに気づきました。
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/api/token"),
Provider = new ApplicationOAuthProvider(PublicClientId,UserManagerFactory) ,
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
これは、私の最新のプロジェクトには適していません。私は、短命の bearer_token を配布し、その更新は
refresh_token
たくさんググってみましたが、参考になるものが見つかりません。
というわけで、なんとかここまでたどり着きました。今、私は "WTF do I now" のポイントに到達しています。
を書きました。
RefreshTokenProvider
を実装した
IAuthenticationTokenProvider
と同じように
RefreshTokenProvider
プロパティに
OAuthAuthorizationServerOptions
クラスのプロパティです。
public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
{
private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string, AuthenticationTicket>();
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
var guid = Guid.NewGuid().ToString();
_refreshTokens.TryAdd(guid, context.Ticket);
// hash??
context.SetToken(guid);
}
public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
AuthenticationTicket ticket;
if (_refreshTokens.TryRemove(context.Token, out ticket))
{
context.SetTicket(ticket);
}
}
public void Create(AuthenticationTokenCreateContext context)
{
throw new NotImplementedException();
}
public void Receive(AuthenticationTokenReceiveContext context)
{
throw new NotImplementedException();
}
}
// Now in my Startup.Auth.cs
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/api/token"),
Provider = new ApplicationOAuthProvider(PublicClientId,UserManagerFactory) ,
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(2),
AllowInsecureHttp = true,
RefreshTokenProvider = new RefreshTokenProvider() // This is my test
};
これで、誰かが
bearer_token
を送信するようになりました。
refresh_token
を送信しています。
では、この refresh_token を使って、どのように新しい
bearer_token
を取得するには、おそらく特定の HTTP ヘッダーを設定してトークン エンドポイントにリクエストを送信する必要があるのではないでしょうか。
入力しながら声に出して考えています... refresh_tokenの有効期限は、次のように処理する必要があります。
SimpleRefreshTokenProvider
? クライアントはどのようにして新しい
refresh_token
?
私はこれを間違いたくないし、ある種の標準に従いたいので、いくつかの読み物/ドキュメントがあれば本当に助かります。
どのように解決するのですか?
Bearer(以下access_tokenと呼ぶ)とRefresh Tokenを使ってOWIN Serviceを実装したところです。これに対する私の洞察は、異なるフローを使用することができるということです。つまり、access_tokenとrefresh_tokenの有効期限をどのように設定するかは、使いたいフローに依存するということです。
私は2つの フロー A と B を追加してください(Bの流れにすることをお勧めします)。
A) access_tokenとrefresh_tokenの有効期限は、デフォルトで1200秒または20分となっており、同じです。このフローでは、まずクライアントがログインデータと共にclient_idとclient_secretを送信し、access_token、refresh_token、expiration_timeを取得する必要があります。refresh_tokenにより、20分間(またはOAuthAuthorizationServerOptionsのAccessTokenExpireTimeSpanを設定した時間)新しいaccess_tokenを取得することが可能になりました。access_tokenとrefresh_tokenの有効期限は同じなので、クライアントは有効期限が切れる前に新しいaccess_tokenを取得する責任があります!例えば、クライアントはaccess_tokenを送信することができます。例えば、クライアントはあなたのトークンエンドポイントにリフレッシュPOSTコールを送信し、ボディを送ることができます。
grant_type=refresh_token&client_id=xxxxxx&refresh_token=xxxxxxxx-xxxx-xxxx-xxxx-xxxxx
で、トークンの期限切れを防ぐために、例えば19分後に新しいトークンを取得します。
B)
このフローでは、access_tokenに短期間の有効期限を、refresh_tokenに長期間の有効期限を設定したいと思います。テスト用に、access_tokenの有効期限を10秒に設定したとします (
AccessTokenExpireTimeSpan = TimeSpan.FromSeconds(10)
) とし、refresh_token を 5 分に設定します。さて、ここからが refresh_token の有効期限を設定する興味深い部分です。SimpleRefreshTokenProviderクラスのcreateAsync関数でこのように行います。
var guid = Guid.NewGuid().ToString();
//copy properties and set the desired lifetime of refresh token
var refreshTokenProperties = new AuthenticationProperties(context.Ticket.Properties.Dictionary)
{
IssuedUtc = context.Ticket.Properties.IssuedUtc,
ExpiresUtc = DateTime.UtcNow.AddMinutes(5) //SET DATETIME to 5 Minutes
//ExpiresUtc = DateTime.UtcNow.AddMonths(3)
};
/*CREATE A NEW TICKET WITH EXPIRATION TIME OF 5 MINUTES
*INCLUDING THE VALUES OF THE CONTEXT TICKET: SO ALL WE
*DO HERE IS TO ADD THE PROPERTIES IssuedUtc and
*ExpiredUtc to the TICKET*/
var refreshTokenTicket = new AuthenticationTicket(context.Ticket.Identity, refreshTokenProperties);
//saving the new refreshTokenTicket to a local var of Type ConcurrentDictionary<string,AuthenticationTicket>
// consider storing only the hash of the handle
RefreshTokens.TryAdd(guid, refreshTokenTicket);
context.SetToken(guid);
これで、クライアントは
access_token
が期限切れになったとき、クライアントはトークン・エンドポイントに refresh_token を使って POS コールを送ることができます。呼び出しのボディ部分は次のようになります。
grant_type=refresh_token&client_id=xxxxxx&refresh_token=xxxxxxxx-xxxx-xxxx-xxxx-xx
重要なことは、このコードをCreateAsync関数だけでなく、Create関数でも使用したい場合があることです。そのため、上記のコードには独自の関数(例えばCreateTokenInternalという関数)を使用することを検討する必要があります。 ここでは、refresh_tokenフローを含むさまざまなフローの実装を見つけることができます。 (ただし、refresh_tokenの有効期限を設定しない場合)
githubにあるIAuthenticationTokenProviderの実装例を一つ紹介します。 (refresh_tokenの有効期限を設定したもの)
OAuth 仕様書と Microsoft API Documentation 以外の資料でお役に立てず、申し訳ありません。ここにリンクを貼りたいのですが、私のレピュテーションでは2つ以上のリンクを貼ることができません......。
私は、access_tokenの有効期限と異なるrefresh_tokenの有効期限を持つOAuth2.0を実装しようとするときに、これが他の人の時間の節約になることを願っています。私はウェブ上で実装例を見つけることができず(上記のリンク先のthinktectureのものを除く)、それが私のために動作するまで何時間も調査しました。
新しい情報です。私の場合、トークンを受け取るために 2 つの異なる可能性があります。1つは、有効なaccess_tokenを受信することです。この場合、次のデータを含む application/x-www-form-urlencoded 形式の文字列ボディを持つ POST コールを送信する必要があります。
client_id=YOURCLIENTID&grant_type=password&username=YOURUSERNAME&password=YOURPASSWORD
次に、access_token が有効でなくなった場合、refresh_token を試すには、以下の形式の文字列を本文に含む POST コールを送信します。
application/x-www-form-urlencoded
という形式の文字列のボディに、以下のデータを記述してPOSTを送信します。
grant_type=refresh_token&client_id=YOURCLIENTID&refresh_token=YOURREFRESHTOKENGUID
関連
-
[解決済み】「未割り当てのローカル変数を使用」とはどういう意味ですか?
-
[解決済み】文字列が有効な DateTime " format dd/MM/yyyy " として認識されなかった。
-
[解決済み】Excel "外部テーブルが期待された形式ではありません。"
-
[解決済み】「namespace x already contains a definition for x」エラーの修正方法は?VS2010にコンバートした後に発生しました。
-
[解決済み] EntityTypeにキーが定義されていないエラー
-
[解決済み】Visual Studio: 操作を完了できませんでした。パラメータが正しくありません
-
[解決済み】「namespace」なのに「type」のように使われる。
-
[解決済み】別のスレッドがこのオブジェクトを所有しているため、呼び出し側のスレッドはこのオブジェクトにアクセスできない
-
[解決済み] カタナ」と「オウイン」をわかりやすく説明すると?
-
[解決済み】OAuth 2は、Security Tokenを使用したリプレイ攻撃などからどのように保護するのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】指定されたキャストが有効でない?
-
[解決済み】プログラム実行中に1秒待つ
-
[解決済み】Ajax処理で「無効なJSONプリミティブ」と表示される件
-
[解決済み】ORA-01008: すべての変数がバインドされていません。これらはバインドされています。
-
[解決済み】WPFでXamlファイルにコメントを追加する方法は?
-
[解決済み】EF 5 Enable-Migrations : アセンブリにコンテキストタイプが見つかりませんでした
-
[解決済み] UnityでOnCollisionEnterが呼ばれない
-
[解決済み】WSACancelBlockingCallの例外について
-
[解決済み] [Solved] .NETでスレッドの終了を待つには?
-
[解決済み】スレッド終了またはアプリケーションの要求により、I/O操作が中断されました。