2016-10-01 4 views
5

MVCコアアプリケーションを使用しているときにアクセスとリフレッシュを最適に実装する方法を読んできましたそれには多くのAjaxコールがあります。私は正しいと思っていますが、これを行うより良い方法があるかどうかを知りたがっています。この投稿を編集して、この情報を探している人の参考にすることができます。MVCコアでアクセストークンをリフレッシュするベストプラクティスIdentity Server 4を使用してビューとリソースの両方を含むアプリケーション

私の設定: 私は多くのJavaScriptを持つMVCコアアプリケーションを持っています。 JavaScriptは、ajax呼び出しを使用してjsonアクションまたは呼び出しアクションを取得しています。

ユーザーがCookie認証を使用して私のapiにアクセスできないようにするために、app.Mapを使用してアプリケーションを2つに分割しています。ユーザーがアイデンティティトークンを使用してビューにアクセスできる場所と、アクセストークンが必要な場所。私はアクセストークンをリフレッシュする必要がある時を保つためにクッキーを追加しています。

Startup.cs(私はにとって必須ではありません部品を取り外す)

app.UseCookieAuthentication(new CookieAuthenticationOptions 
    { 
    AuthenticationScheme = "Cookies", 
    AutomaticAuthenticate = true, 
    ExpireTimeSpan = TimeSpan.FromMinutes(60) 
    }); 

    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 

    var oidcOptions = new OpenIdConnectOptions 
    { 
    AuthenticationScheme = "oidc", 
    SignInScheme = "Cookies", 

    Authority = LoginServerUrl, 
    RequireHttpsMetadata = false, 
    ClientId = "MyApp", 
    ClientSecret = "*****", 
    ResponseType = "code id_token", 
    SaveTokens = true, 
    Events = new OpenIdConnectEvents() 
    { 
     OnTicketReceived = async notification => 
     { 
     notification.Response.Cookies.Append("NextAccessTokenRefresh", DateTime.Now.AddMinutes(30).ToString()); 
     notification.Response.Cookies.Delete("AccessToken"); 
     }, 
    }, 

    TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters 
    { 
     NameClaimType = JwtClaimTypes.Name, 
     RoleClaimType = JwtClaimTypes.Role, 
    }, 
    }; 

    oidcOptions.Scope.Clear(); 
    oidcOptions.Scope.Add("openid"); 
    oidcOptions.Scope.Add("roles"); 
    oidcOptions.Scope.Add("offline_access"); 

    app.UseOpenIdConnectAuthentication(oidcOptions); 

    app.Map("/api", (context) => 
    { 
    var bearerTokenOptions = new IdentityServerAuthenticationOptions 
    { 
     AuthenticationScheme = "Bearer", 
     Authority = LoginServerUrl,, 
     RequireHttpsMetadata = false, 
     ScopeName = "MyApi", 
     AutomaticAuthenticate = true 
    }; 

    context.UseIdentityServerAuthentication(bearerTokenOptions); 
    context.UseMvcWithDefaultRoute(); 
    }); 

すべてのAJAXは、アクションは次のURL/API/[コントローラ]/[アクション]を使用して行われコントローラに呼び出します。

アイデンティティトークンを使用して私のapiにアクセスしたくないので、コントローラアクションにAuthorize(ActiveAuthenticationSchemes = "Bearer")属性を追加します。だから今、私のコントローラのアクションは、次のようになりますジャバスクリプトによって呼び出さなっている可能性も:

[HttpPost, Authorize(ActiveAuthenticationSchemes = "Bearer")] 
public async Task<JsonResult> DoStuff() 
{ 
} 

APIリソースにアクセスする必要があるjavascriptの、のcontrolerが最初のアクセストークンをretrivesとカスタムJavaScriptのinitを使用したJavaScriptにそれを注入した場合方法。

このC#メソッドは、アクセスCookieをリフレッシュおよび取得する役割を担います。

beforeSend: function(xhr, settings) { xhr.setRequestHeader('Authorization','Bearer ' + accessToken); } 

ザッツそれ:私は次のパラメータを追加したすべての私の$アヤックスで

public async Task<string> GetAccessTokenAsync() 
{ 
    var accessToken = _contextAccessor.HttpContext.Request.Cookies["AccessToken"]; 
    var nextAccessTokenRefresh = _contextAccessor.HttpContext.Request.Cookies["NextAccessTokenRefresh"]; 
    if (string.IsNullOrEmpty(nextAccessTokenRefresh) || string.IsNullOrEmpty(accessToken) || DateTime.Parse(nextAccessTokenRefresh) <= DateTime.Now) 
    { 
    var refreshToken = await _contextAccessor.HttpContext.Authentication.GetTokenAsync("refresh_token"); 
    var tokenClient = new TokenClient(_appSettings.LoginServerUrl + "/connect/token", _appSettings.LoginClientId, _appSettings.LoginClientSecret); 
    var response = await tokenClient.RequestRefreshTokenAsync(refreshToken); 
    accessToken = response.AccessToken; 

    //Set cookies for next refresh 
    _contextAccessor.HttpContext.Response.Cookies.Append("NextAccessTokenRefresh", DateTime.Now.AddMinutes(30).ToString()); 
    _contextAccessor.HttpContext.Response.Cookies.Append("AccessToken", response.AccessToken); 
    } 

    return accessToken; 
} 

。デフォルトのアクセストークンの有効期限は1時間です。私はいつもその半分の時間後にリフレッシュします。私の質問に今

  1. 私はどのような方法で自分のコードを向上させることができますか?
  2. このようなセキュリティ関連のリスクはありますか。
  3. OnTicketReceivedのアクセストークンを取得できますか?
+1

私は、オフトピックとして、この質問を閉じるために投票しています。コードレビューは話題外です。 http://codereview.stackexchange.com/ –

+0

私はそれが少し話題だが、ID4を使っている人の多くはこの情報を探していることを知っています。私は多くの異なるフォーラムで同じ質問が現れるのを見ているので、私はそれらをすべて回答するためにここに投稿すると思った。私はブログ記事を作ったかもしれないが、devsはここで情報を探している。このような情報を見つける場所ではありませんか? –

+0

次に、あなたは1)コードレビューを求めていない、2)ベストプラクティス(通常は単に「主に意見ベース」である)を求めないように、別の方法でフレーズしようとするべきです。 –

答えて

3

私のコードを改善することはできますか?

あなた Startup.cs

は次のようなものでなければなりません(唯一の '/ API' パスのMap動作するため、より多くの情報がhttps://docs.asp.net/en/latest/fundamentals/middleware.html#run-map-and-useを参照してください。):

app.MapWhen(context => !context.Request.Path.Value.StartsWith("/api"), builder=> 
{ 
    app.UseCookieAuthentication(options); 
    ... 
    app.UseOpenIdConnectAuthentication(oidcOptions); 
    .... 
}); 

app.MapWhen(context => context.Request.Path.Value.StartsWith("/api"), builder=> 
{ 
    var bearerTokenOptions = new IdentityServerAuthenticationOptions 
    { 
     AuthenticationScheme = "Bearer", 
     Authority = LoginServerUrl,, 
     RequireHttpsMetadata = false, 
     ScopeName = "MyApi", 
     AutomaticAuthenticate = true 
    }; 

    context.UseIdentityServerAuthentication(bearerTokenOptions); 
    context.UseMvcWithDefaultRoute(); 
}); 

2点目、あなたのクッキーは時間が60分で期限切れになり、この場合、更新トークンの有効期間は60分になります。私はこれが問題かもしれないと思う。

このようなセキュリティ関連のリスクはありますか。

リフレッシュトークンを使用するための十分な経験がないため、実装が安全であるとは言えません。しかし、リフレッシュトークン(あなたの実装のために)複雑さもセキュリティリスク(これは私の意見であり、私はセキュリティ専門家ではない)と考えています。私は暗黙的なフロー(単純さのために)を持つ長生命のアクセストークンのみを使用します。

OnTicketReceivedでアクセストークンを取得できますか。

はい、次のことができます。それはコードレビューを求めているので、

OnTicketReceived = ctx => 
{ 
    var token = ctx.Ticket.Properties.GetTokenValue("access_token"); 
    ... 
} 
+0

あなたの素晴らしい答えをありがとう。より具体的になるようにマップパスを変更し、OnTicketReceivedにトークンをクッキーに格納します。これにより、サーバーへのラウンドトリップが削減されます。 –

+0

私は長生きのアクセストークンを使用することを考えていましたが、ユーザの介入なしに必要になったときにトークンをリフレッシュすることで安全にすることができます。もう少し複雑ですが、私は自分のサーバーに「クライアントシークレット」しか保存していないので、リフレッシュトークンを使っても問題ないと思います。 –

+0

長寿命のアクセストークンを使用することは私の好み(私はそれを使用すると言うことはできません)です。私は可能な限り複雑さを避け、私の意見では、複雑さはセキュリティリスクです。 –

関連する問題