/// <summary>GetClaims</summary> /// <param name="userName">string</param> /// <param name="roles">string</param> /// <param name="scopes">string</param> /// <param name="ipAddress">string</param> public static void GetClaims(out string userName, out string roles, out string scopes, out string ipAddress) { // MyHttpContext.Current.User.Identity側ではなく、Identities側に入っている。 // Identityは認証ミドルウェアを使用する必要がある?(coreでjwtをどう処理するのか?) IEnumerable <Claim> claims = MyBaseAsyncApiController.GetRawClaims(); if (claims == null) { // claims == null userName = "******"; roles = ""; scopes = ""; ipAddress = ""; } else { // claims != null Claim claim = null; claim = claims.FirstOrDefault(c => c.Type == ClaimTypes.Name); if (claim == null) { userName = "******"; } else { userName = claim.Value; } claim = claims.FirstOrDefault(c => c.Type == ClaimTypes.Role); if (claim == null) { roles = ""; } else { roles = claim.Value; } claim = claims.FirstOrDefault(c => c.Type == OAuth2AndOIDCConst.UrnScopesClaim); if (claim == null) { scopes = ""; } else { scopes = claim.Value; } claim = claims.FirstOrDefault(c => c.Type == "IpAddress"); if (claim == null) { ipAddress = ""; } else { ipAddress = claim.Value; } } }
/// <summary> /// アクション メソッドの呼び出し後に発生します。 /// https://msdn.microsoft.com/ja-jp/library/dn573277.aspx /// </summary> /// <param name="actionExecutedContext">HttpActionExecutedContext</param> /// <param name="cancellationToken">CancellationToken</param> public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken) { // Calling base class method. await base.OnActionExecutedAsync(actionExecutedContext, cancellationToken); // 性能測定終了 this.perfRec.EndsPerformanceRecord(); // ------------ // メッセージ部 // ------------ // ユーザ名, IPアドレス, // レイヤ, 画面名, コントロール名, 処理名 // 処理時間(実行時間), 処理時間(CPU時間) // エラーメッセージID, エラーメッセージ等 // ------------ // Claimを取得する。 string userName, roles, scopes, ipAddress; MyBaseAsyncApiController.GetClaims(out userName, out roles, out scopes, out ipAddress); string strLogMessage = "," + userName + //this.UserInfo.UserName + "," + ipAddress + //this.UserInfo.IPAddress + "," + "<-----" + "," + this.ControllerName + "," + this.ActionName + "(OnActionExecuted)" + "," + perfRec.ExecTime + "," + perfRec.CpuTime; LogIF.InfoLog("ACCESS", strLogMessage); }
/// <summary>GetClaims</summary> /// <param name="userName">string</param> /// <param name="roles">string</param> /// <param name="scopes">string</param> /// <param name="ipAddress">string</param> public static void GetClaims(out string userName, out string roles, out string scopes, out string ipAddress) { IEnumerable <Claim> claims = MyBaseAsyncApiController.GetRawClaims(); if (claims == null) { // claims == null userName = "******"; roles = ""; scopes = ""; ipAddress = ""; } else { // claims != null Claim claim = null; claim = claims.FirstOrDefault(c => c.Type == ClaimTypes.Name); if (claim == null) { userName = "******"; } else { userName = claim.Value; } claim = claims.FirstOrDefault(c => c.Type == ClaimTypes.Role); if (claim == null) { roles = ""; } else { roles = claim.Value; } claim = claims.FirstOrDefault(c => c.Type == OAuth2AndOIDCConst.UrnScopesClaim); if (claim == null) { scopes = ""; } else { scopes = claim.Value; } claim = claims.FirstOrDefault(c => c.Type == "IpAddress"); if (claim == null) { ipAddress = ""; } else { ipAddress = claim.Value; } } }
/// <summary>GetClaims</summary> /// <param name="userName">string</param> /// <param name="roles">string</param> /// <param name="scopes">string</param> /// <param name="ipAddress">string</param> public static void GetClaims(out string userName, out string roles, out string scopes, out string ipAddress) { IEnumerable <Claim> claims = MyBaseAsyncApiController.GetRawClaims(); userName = claims.FirstOrDefault(c => c.Type == ClaimTypes.Name).Value; roles = claims.FirstOrDefault(c => c.Type == ClaimTypes.Role).Value; scopes = claims.FirstOrDefault(c => c.Type == OAuth2AndOIDCConst.UrnScopesClaim).Value; ipAddress = claims.FirstOrDefault(c => c.Type == "IpAddress").Value; }
/// <summary>GetClaims</summary> /// <param name="userName">string</param> /// <param name="roles">string</param> /// <param name="scopes">string</param> /// <param name="ipAddress">string</param> public static void GetClaims(out string userName, out string roles, out string scopes, out string ipAddress) { // MyHttpContext.Current.User.Identity側ではなく、Identities側に入っている。 // Identityは認証ミドルウェアを使用する必要がある?(coreでjwtをどう処理するのか?) IEnumerable <Claim> claims = MyBaseAsyncApiController.GetRawClaims(); userName = claims.FirstOrDefault(c => c.Type == ClaimTypes.Name).Value; roles = claims.FirstOrDefault(c => c.Type == ClaimTypes.Role).Value; scopes = claims.FirstOrDefault(c => c.Type == OAuth2AndOIDCConst.UrnScopesClaim).Value; ipAddress = claims.FirstOrDefault(c => c.Type == "IpAddress").Value; }
/// <summary>GetRawClaims</summary> /// <returns>IEnumerable(Claim)</returns> public static IEnumerable <Claim> GetRawClaims() { ClaimsIdentity claimsIdentity = MyBaseAsyncApiController.GetClaimsIdentity(); if (claimsIdentity == null) { return(null); } else { return(claimsIdentity.Claims); } }
/// <summary> /// アクション メソッドの呼び出し前に発生します。 /// https://msdn.microsoft.com/ja-jp/library/dn573278.aspx /// </summary> /// <param name="actionContext">HttpActionContext</param> /// <param name="cancellationToken">CancellationToken</param> public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken) { // Controller・Action名を取得する。 this.GetControllerAndActionName(actionContext); // Claimを取得する。 string userName, roles, scopes, ipAddress; MyBaseAsyncApiController.GetClaims(out userName, out roles, out scopes, out ipAddress); // 権限チェック ------------------------------------------------ // ・・・ // ------------------------------------------------------------- // 閉塞チェック ------------------------------------------------ // ・・・ // ------------------------------------------------------------- // 性能測定開始 this.perfRec = new PerformanceRecorder(); this.perfRec.StartsPerformanceRecord(); // Calling base class method. await base.OnActionExecutingAsync(actionContext, cancellationToken); // ------------ // メッセージ部 // ------------ // ユーザ名, IPアドレス, // レイヤ, 画面名, コントロール名, 処理名 // 処理時間(実行時間), 処理時間(CPU時間) // エラーメッセージID, エラーメッセージ等 // ------------ string strLogMessage = "," + userName + //this.UserInfo.UserName + "," + ipAddress + //this.UserInfo.IPAddress + "," + "----->" + "," + this.ControllerName + "," + this.ActionName + "(OnActionExecuting)"; LogIF.InfoLog("ACCESS", strLogMessage); }
/// <summary>エラーログの出力</summary> /// <param name="exceptionContext">HttpActionExecutedContext</param> private void OutputErrorLog(ExceptionContext exceptionContext) { // 非同期ControllerのInnerException対策(底のExceptionを取得する)。 Exception ex = exceptionContext.Exception; Exception bottomException = ex; while (bottomException.InnerException != null) { bottomException = bottomException.InnerException; } // ------------ // メッセージ部 // ------------ // ユーザ名, IPアドレス, // レイヤ, 画面名, コントロール名, 処理名 // 処理時間(実行時間), 処理時間(CPU時間) // エラーメッセージID, エラーメッセージ等 // ------------ // Claimを取得する。 string userName, roles, scopes, ipAddress; MyBaseAsyncApiController.GetClaims(out userName, out roles, out scopes, out ipAddress); string strLogMessage = "," + userName + // (this.UserInfo != null ? this.UserInfo.UserName : "******") + "," + ipAddress + //(this.UserInfo != null ? this.UserInfo.IPAddress : "null") + "," + "<-----" + "," + this.ControllerName + "," + this.ActionName + "(ExecuteExceptionFilterAsync)" + "," + //this.perfRec.ExecTime + "," + //this.perfRec.CpuTime + "," + GetExceptionMessageID(bottomException) + "," + bottomException.Message + "\r\n" + "," + bottomException.StackTrace + "\r\n" + "," + ex.ToString(); // Exception.ToString()はRootのExceptionに対して行なう。 LogIF.ErrorLog("ACCESS", strLogMessage); }
/// <summary>ユーザ情報を取得する</summary> /// <param name="authorizationContext">AuthorizationFilterContext</param> /// <remarks>awaitするメソッドを追加して呼ぶ可能性も高いのでasyncを付与</remarks> private async Task GetUserInfoAsync(AuthorizationFilterContext authorizationContext) { // Authorization: <type> <credentials> if (this.HttpAuthHeader == EnumHttpAuthHeader.None) { // 認証なし return; } else if (this.HttpAuthHeader.HasFlag(EnumHttpAuthHeader.Basic)) { // Basic認証の認証アルゴリズムを追加 // Authorization: Basic XXXXXXXXXX return; } else if (this.HttpAuthHeader.HasFlag(EnumHttpAuthHeader.Bearer)) { // Bearer認証の認証アルゴリズムを追加 -------------------------- // Authorization: Bearer XXXXXXXXXX // JWTアサーションを処理し、認証、UserInfoを生成するなど。 // ------------------------------------------------------------- List <Claim> claims = null; if (authorizationContext.HttpContext.Request.Headers != null) { StringValues authHeaders = ""; try { if (authorizationContext.HttpContext.Request.Headers.TryGetValue("Authorization", out authHeaders)) { string access_token = authHeaders[0].Split(' ')[1]; string sub = ""; List <string> roles = null; List <string> scopes = null; JObject jobj = null; if (AccessToken.Verify(access_token, out sub, out roles, out scopes, out jobj)) { // ActionFilterAttributeとApiController間の情報共有はcontext.Principalを使用する。 // ★ 必要であれば、他の業務共通引継ぎ情報などをロードする。 claims = new List <Claim>() { new Claim(ClaimTypes.Name, sub), new Claim(ClaimTypes.Role, string.Join(",", roles)), new Claim(OAuth2AndOIDCConst.UrnScopesClaim, string.Join(",", scopes)), new Claim(OAuth2AndOIDCConst.UrnAudienceClaim, (string)jobj[OAuth2AndOIDCConst.aud]), new Claim("IpAddress", MyBaseAsyncApiController.GetClientIpAddress()) }; // ClaimsPrincipalを設定 MyHttpContext.Current.User = new ClaimsPrincipal(new ClaimsIdentity(claims, "Token")); return; } else { // JWTの内容検証に失敗 } } else { // Authorization HeaderがBearerでない。 } } catch { // 例外発生 ≒ 未認証扱い。 } } else { // Authorization Headerが存在しない。 } #region 未認証状態の場合の扱い if (this.HttpAuthHeader.HasFlag(EnumHttpAuthHeader.None)) { // 未認証状態のclaimsを作成格納 claims = new List <Claim>() { new Claim(ClaimTypes.Name, "未認証"), new Claim(ClaimTypes.Role, ""), new Claim(OAuth2AndOIDCConst.UrnScopesClaim, ""), new Claim(OAuth2AndOIDCConst.UrnAudienceClaim, ""), new Claim("IpAddress", MyBaseAsyncApiController.GetClientIpAddress()) }; MyHttpContext.Current.User.AddIdentity(new ClaimsIdentity(claims, "Token")); } else { // 認証エラーを返す。 // ASP.NET Core MVCで403エラーをクライアントへ返す - Living Absurd World // https://blog.hmatoba.net/Article/144 authorizationContext.Result = new UnauthorizedResult(); } return; #endregion } }
/// <summary> /// アクション メソッドの呼び出し前に発生します(netcore)。 /// https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.aspnetcore.mvc.filters.actionfilterattribute.onactionexecutionasync /// </summary> /// <param name="context">HttpActionContext</param> /// <param name="next">ActionExecutionDelegate</param> public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { #region OnActionExecutingAsyncから移行 // Controller・Action名を取得する。 this.GetControllerAndActionName(context); // Claimを取得する。 string userName, roles, scopes, ipAddress; MyBaseAsyncApiController.GetClaims(out userName, out roles, out scopes, out ipAddress); // 権限チェック ------------------------------------------------ // ・・・ // ------------------------------------------------------------- // 閉塞チェック ------------------------------------------------ // ・・・ // ------------------------------------------------------------- // 性能測定開始 this.perfRec = new PerformanceRecorder(); this.perfRec.StartsPerformanceRecord(); // ------------ // メッセージ部 // ------------ // ユーザ名, IPアドレス, // レイヤ, 画面名, コントロール名, 処理名 // 処理時間(実行時間), 処理時間(CPU時間) // エラーメッセージID, エラーメッセージ等 // ------------ string strLogMessage = "," + userName + //this.UserInfo.UserName + "," + ipAddress + //this.UserInfo.IPAddress + "," + "----->" + "," + this.ControllerName + "," + this.ActionName + "(OnActionExecuting)"; LogIF.InfoLog("ACCESS", strLogMessage); // 性能測定終了 this.perfRec.EndsPerformanceRecord(); #endregion await base.OnActionExecutionAsync(context, next); #region OnActionExecutedAsyncから移行 // ------------ // メッセージ部 // ------------ // ユーザ名, IPアドレス, // レイヤ, 画面名, コントロール名, 処理名 // 処理時間(実行時間), 処理時間(CPU時間) // エラーメッセージID, エラーメッセージ等 // ----------- strLogMessage = "," + userName + //this.UserInfo.UserName + "," + ipAddress + //this.UserInfo.IPAddress + "," + "<-----" + "," + this.ControllerName + "," + this.ActionName + "(OnActionExecuted)" + "," + perfRec.ExecTime + "," + perfRec.CpuTime; LogIF.InfoLog("ACCESS", strLogMessage); #endregion }
/// <summary>ユーザ情報を取得する</summary> /// <param name="authenticationContext">HttpAuthenticationContext</param> private async Task GetUserInfoAsync(HttpAuthenticationContext authenticationContext) { // Authorization: <type> <credentials> if (this.HttpAuthHeader == EnumHttpAuthHeader.None) { // 認証なし return; } else if (this.HttpAuthHeader.HasFlag(EnumHttpAuthHeader.Basic)) { // Basic認証の認証アルゴリズムを追加 // Authorization: Basic XXXXXXXXXX return; } else if (this.HttpAuthHeader.HasFlag(EnumHttpAuthHeader.Bearer)) { // Bearer認証の認証アルゴリズムを追加 -------------------------- // Authorization: Bearer XXXXXXXXXX // JWTアサーションを処理し、認証、UserInfoを生成するなど。 // ------------------------------------------------------------- List <Claim> claims = null; if (authenticationContext.Request.Headers.Authorization != null) { try { if (authenticationContext.Request.Headers.Authorization.Scheme.ToLower() == "bearer") { string access_token = authenticationContext.Request.Headers.Authorization.Parameter; string sub = ""; List <string> roles = null; List <string> scopes = null; JObject jobj = null; if (AccessToken.Verify(access_token, out sub, out roles, out scopes, out jobj)) { // ActionFilterAttributeとApiController間の情報共有はcontext.Principalを使用する。 // ★ 必要であれば、他の業務共通引継ぎ情報などをロードする。 claims = new List <Claim>() { new Claim(ClaimTypes.Name, sub), new Claim(ClaimTypes.Role, string.Join(",", roles)), new Claim(OAuth2AndOIDCConst.UrnScopesClaim, string.Join(",", scopes)), new Claim(OAuth2AndOIDCConst.UrnAudienceClaim, (string)jobj[OAuth2AndOIDCConst.aud]), new Claim("IpAddress", MyBaseAsyncApiController.GetClientIpAddress(authenticationContext.Request)) }; // The request message contains valid credential. authenticationContext.Principal = new ClaimsPrincipal( new List <ClaimsIdentity> { new ClaimsIdentity(claims, "Token") }); return; } else { // JWTの内容検証に失敗 } } else { // Authorization HeaderがBearerでない。 } } catch { // 例外発生 ≒ 未認証扱い。 } } else { // Authorization Headerが存在しない。 } #region 未認証状態の場合の扱い if (this.HttpAuthHeader.HasFlag(EnumHttpAuthHeader.None)) { // 未認証状態のclaimsを作成格納 claims = new List <Claim>() { new Claim(ClaimTypes.Name, "未認証"), new Claim(ClaimTypes.Role, ""), new Claim(OAuth2AndOIDCConst.UrnScopesClaim, ""), new Claim(OAuth2AndOIDCConst.UrnAudienceClaim, ""), new Claim("IpAddress", MyBaseAsyncApiController.GetClientIpAddress(authenticationContext.Request)) }; authenticationContext.Principal = new ClaimsPrincipal(new List <ClaimsIdentity> { new ClaimsIdentity(claims, "Token") }); } else { // 認証エラーを返す。 // ASP.NET Web API 2 | Microsoft Docs // https://docs.microsoft.com/ja-jp/aspnet/web-api/overview/security/authentication-filters authenticationContext.ErrorResult = new AuthenticationFailureResult( authenticationContext.Request, "Bearer Credentials is invalid."); } return; #endregion } }
/// <summary>GetRawClaims</summary> /// <returns>IEnumerable(Claim)</returns> public static IEnumerable <Claim> GetRawClaims() { return(MyBaseAsyncApiController.GetClaimsIdentity().Claims); }
/// <summary>ユーザ情報を取得する</summary> /// <param name="authorizationContext">AuthorizationFilterContext</param> /// <remarks>awaitするメソッドを追加して呼ぶ可能性も高いのでasyncを付与</remarks> private async Task GetUserInfoAsync(AuthorizationFilterContext authorizationContext) { // カスタム認証処理 -------------------------------------------- // Authorization: Bearer ヘッダから // JWTアサーションを処理し、認証、UserInfoを生成するなど。 // ------------------------------------------------------------- List <Claim> claims = null; if (authorizationContext.HttpContext.Request.Headers != null) { StringValues authHeaders = ""; if (authorizationContext.HttpContext.Request.Headers.TryGetValue("Authorization", out authHeaders)) { string access_token = authHeaders[0].Split(' ')[1]; string sub = ""; List <string> roles = null; List <string> scopes = null; JObject jobj = null; if (AccessToken.Verify(access_token, out sub, out roles, out scopes, out jobj)) { // ActionFilterAttributeとApiController間の情報共有はcontext.Principalを使用する。 // ★ 必要であれば、他の業務共通引継ぎ情報などをロードする。 claims = new List <Claim>() { new Claim(ClaimTypes.Name, sub), new Claim(ClaimTypes.Role, string.Join(",", roles)), new Claim(OAuth2AndOIDCConst.UrnScopesClaim, string.Join(",", scopes)), new Claim(OAuth2AndOIDCConst.UrnAudienceClaim, (string)jobj[OAuth2AndOIDCConst.aud]), new Claim("IpAddress", MyBaseAsyncApiController.GetClientIpAddress()) }; // ClaimsPrincipalを設定 MyHttpContext.Current.User = new ClaimsPrincipal(new ClaimsIdentity(claims, "Token")); return; } else { // JWTの内容検証に失敗 } } else { // Authorization HeaderがBearerでない。 } } else { // Authorization Headerが存在しない。 } #region 未認証状態の場合の扱い // The request message contains invalid credential //context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request); // 未認証状態のclaimsを作成格納 claims = new List <Claim>() { new Claim(ClaimTypes.Name, "未認証"), new Claim(ClaimTypes.Role, ""), new Claim(OAuth2AndOIDCConst.UrnScopesClaim, ""), new Claim(OAuth2AndOIDCConst.UrnAudienceClaim, ""), new Claim("IpAddress", MyBaseAsyncApiController.GetClientIpAddress()) }; // The request message contains valid credential. MyHttpContext.Current.User.AddIdentity(new ClaimsIdentity(claims, "Token")); return; #endregion }
/// <summary>ユーザ情報を取得する</summary> /// <param name="authenticationContext">HttpAuthenticationContext</param> private async Task GetUserInfoAsync(HttpAuthenticationContext authenticationContext) { // カスタム認証処理 -------------------------------------------- // Authorization: Bearer ヘッダから // JWTアサーションを処理し、認証、UserInfoを生成するなど。 // ------------------------------------------------------------- List <Claim> claims = null; if (authenticationContext.Request.Headers.Authorization.Scheme.ToLower() == "bearer") { string access_token = authenticationContext.Request.Headers.Authorization.Parameter; string sub = ""; List <string> roles = null; List <string> scopes = null; JObject jobj = null; if (JwtToken.Verify(access_token, out sub, out roles, out scopes, out jobj)) { // ActionFilterAttributeとApiController間の情報共有はcontext.Principalを使用する。 // ★ 必要であれば、他の業務共通引継ぎ情報などをロードする。 claims = new List <Claim>() { new Claim(ClaimTypes.Name, sub), new Claim(ClaimTypes.Role, string.Join(",", roles)), new Claim("Scopes", string.Join(",", scopes)), new Claim("IpAddress", MyBaseAsyncApiController.GetClientIpAddress(authenticationContext.Request)) }; // The request message contains valid credential authenticationContext.Principal = new ClaimsPrincipal(new List <ClaimsIdentity> { new ClaimsIdentity(claims, "Token") }); return; } else { // JWTの内容検証に失敗 } } else { // Authorization: Bearer Headerが存在しない。 } // 未認証状態 // The request message contains invalid credential //context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request); claims = new List <Claim>() { new Claim(ClaimTypes.Name, "未認証"), new Claim(ClaimTypes.Role, ""), new Claim("Scopes", ""), new Claim("IpAddress", MyBaseAsyncApiController.GetClientIpAddress(authenticationContext.Request)) }; authenticationContext.Principal = new ClaimsPrincipal(new List <ClaimsIdentity> { new ClaimsIdentity(claims, "Token") }); return; }