多くの ajax 呼び出しを含む MVC コア アプリケーションを使用する場合に、アクセス トークンとリフレッシュ トークンを最適に実装する方法について読んでいます (そしてビデオを見ています)。私はそれが正しかったと思いますが、これを行うより良い方法があるかどうか知りたかっただけです. この情報を探している人の参考になるように、この投稿を編集します。
私のセットアップ: 多くの JavaScript を使用した MVC Core アプリケーションがあります。JavaScript は、ajax 呼び出しを使用して json を取得したり、アクションを呼び出したりしています。
ユーザーが Cookie 認証を使用して API にアクセスできないようにするため、app.Map を使用してアプリケーションを 2 つの部分に分割しています。ユーザーが ID トークンを使用してビューにアクセスできるものと、アクセス トークンを必要とするものです。また、アクセス トークンを更新する必要がある時間を保持するために Cookie を追加しています。
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/[Controller]/[Action] を使用して行われます。
ID トークンを使用して API にアクセスできるようにしたくないので、Authorize(ActiveAuthenticationSchemes = "Bearer") 属性もコントローラー アクションに追加します。したがって、JavaScript によって呼び出されるコントローラー アクションは次のようになります。
[HttpPost, Authorize(ActiveAuthenticationSchemes = "Bearer")]
public async Task<JsonResult> DoStuff()
{
}
JavaScript が API リソースにアクセスする必要がある場合、コントローラーは最初にアクセス トークンを取得し、カスタム JavaScript init メソッドを使用してそれを JavaScript に挿入します。
この C# メソッドは、アクセス Cookie の更新と取得を担当します。
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;
}
すべての $.ajax で、次のパラメーターを追加しました。
beforeSend: function(xhr, settings) { xhr.setRequestHeader('Authorization','Bearer ' + accessToken); }
それでおしまい。デフォルトのアクセス トークンの有効期限は 1 時間です。私はいつもその半分の時間後にそれをリフレッシュします。
今私の質問に:
- 何らかの方法でコードを改善できますか?
- このようにして、セキュリティ関連のリスクが見られますか?
- OnTicketReceived でアクセス トークンを取得できますか?