2017-09-05 3 views
2

첫 번째 .net 코어 2 웹 응용 프로그램 구현을 시작했습니다. 불행하게도 비즈니스 요구 사항으로 인해 사용자는 레거시 양식 로그인을 통해 인증을 받아야하고 사용자 이름/비밀번호는 oracle db로 처리되며 사용자가 인증되면 세션 ID가 생성되어 실행되는 앱의 기본 URL에 추가됩니다. 아주 오래된 학교지만 작동합니다.ClaimsIdentity와의 문제 .NET Core 2 Middleware Solution

세션 ID가 만료되었으므로 세션 ID가 유효해야합니다. 간단히 말해, 쿼리 문자열에서 Oracle API로 가져온 세션 ID를 전달하고 응답은 이름, 성 등과 같은 사용자 정보가 포함 된 개체입니다.

이 API 호출이 성공적으로 완료된 후 새로운 ClaimsIdentity와 Principal을 만들고 SignInAsync() 메서드를 호출하십시오.

저는 현재 내 Startup.cs에 등록한 사용자 정의 미들웨어에서이 작업을 수행합니다. 나는 이것을 Login Controller 메소드에서 일반적인 방법으로 처리 할 것이지만, 내 앱에는 로그인이 없으므로 다른 방법은 볼 수 없지만 내가 작성한 미들웨어에서 볼 수있다.

public class AuthenticationHandler 
{ 
    private readonly RequestDelegate _next; 
    private HttpService _httpService; 

    public AuthenticationHandler(RequestDelegate next, HttpService httpService) 
    { 
     _httpService = httpService; 
     _next = next; 
    } 

    public async Task Invoke(HttpContext context, [FromServices] HttpService httpService) 
    { 
     if (context.Request.Query.Count == 1) 
     { 
      var sessionId = context.Request.Query.FirstOrDefault().Value; 
      var session = await _httpService.ValidateSession(sessionId); 

      if (!string.IsNullOrEmpty(session?.UserId)) 
      { 
       var claims = new List<Claim>() 
       { 
        new Claim(CustomClaimTypes.UserId, session.UserId), 
        new Claim(CustomClaimTypes.BuId, session.BuId), 
        new Claim(CustomClaimTypes.SecurityLevel, session.SecurityLevel) 
       }; 

       var identity = new ClaimsIdentity(claims, "TNReadyEVP"); 
       var principal = new ClaimsPrincipal(identity); 

       await Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.SignInAsync(context, principal); 

       var isIn = principal.Identity.IsAuthenticated; 
       var isAuthed = (context.User.Identity as ClaimsIdentity).IsAuthenticated; 
       await _next.Invoke(context); 
      } 
      else 
      { 
       Terminate(context); 
      } 
     } 

     return; 
    } 

    private async void Terminate(HttpContext context) 
    { 
     context.Response.StatusCode = 401; 
     await context.Response.WriteAsync("Invalid User"); 
     return; 
    } 
} 

public static class MiddlewareExtensions 
{ 
    public static IApplicationBuilder ValidateSession(this IApplicationBuilder builder) 
    { 
     return builder.UseMiddleware<AuthenticationHandler>(); 
    } 
} 

지금까지 그렇게 좋은 해결책이라고 생각합니다. 그러나 아래에 표시된 것처럼 내 API에있는 작은 API를 통해 클레임을 가져 오려고하면 클레임이 비어 있고 User.Identity.Authenticated가 false입니다.

무엇이 여기에 있습니까? 조언 주셔서 감사합니다, 이것은 내가 전에 다루지 않았던 이상한 가장자리 경우 중 하나입니다 ... 따라서 맞춤 미들웨어에 대한 필요성.

[HttpGet("claims")] 
    public async Task<IEnumerable<Claim>> Get() 
    { 
     var claims = (User as ClaimsPrincipal).Claims; 
     return await Task.FromResult(claims); 
    } 

답변

1

정말 자신의 미들웨어를 사용해서는 안됩니다. 내장 된 인증 및 권한 부여 스택은 귀하의 상황을 처리 할 수있을 정도로 강력합니다. 사실 .NET Framework PM의 책임자 인 Barry Dorrans는 ASP.NET 코어 프로젝트 basically† said in a talk의 인증 스택을 담당합니다. 사용 케이스에 맞지 않으면 전자 메일을 삭제해야합니다.

대신이 목적을 위해 자체 인증 처리자를 작성해야합니다. 그렇게하면 추가적인 장애물없이 전체 인증 및 권한 부여 인프라를 확보 할 수 있습니다. 모든 것이 효과가 있습니다.

이렇게하려면 기본적으로 IAuthenticationHandler을 구현하고 등록해야합니다.

나는 당신이하려고하는 것과 비슷한 종류의 일을하기 때문에 CookieAuthenticationHandler을 보길 권한다 : HTTP 요청과 함께 전송 된 정보로 클레임 ID를 재구성한다. 쿠키 데이터 대신 쿼리 인수와 데이터베이스를 사용하고 있습니다.

일반 응용 프로그램 흐름을 어떻게 처리 하느냐에 따라 원격 인증 공급자로 전환하여 쿠키 인증 (다운 된 OAuth 프로세스와 같이)을 결합하는 것조차 고려할 수 있습니다. 요청을 받고 쿠키가 없다면 레거시 로그인 마스크로 리디렉션되는 사용자 정의 인증 처리기에 도전하십시오. 로그인하면 세션 ID가 첨부 된 응용 프로그램의 특수 URL (예 : /signin-session?sessionid=12345)으로 안내합니다. 원격 인증 처리기는 해당 요청을 처리하고 데이터베이스를 쿼리하며 정보에서 ID를 생성하여이를 쿠키 인증 처리기로 전달합니다. 그런 다음 보안 쿠키에 ID를 유지하므로 모든 요청에 ​​대해 더 이상 데이터베이스를 쿼리 할 필요가 없으며 더 이상 모든 단일 URL에서 세션 ID가 필요하지 않습니다.

† 공평하게 말하면 그는 승인 부분에 대해서만 이야기했습니다. 그러나 그가 정말로 강력하기 때문에 그가 또한 전체의 스택을 위해 그것을 의미했다고 확신한다.

+0

자세한 내용은 Thx를 참조하십시오. 당신은 내가 지난 밤에 실험을하고 있었을 때 매우 유용한 점을 만들었습니다. 나는 미들웨어가 의도하지 않은 경우에 작동하도록 강제하는 결론에 도달했습니다. CookieAuthenticationHandler에 대한 문서 검토 및 이에 대한 내용은 다음을 참조하십시오. https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?tabs=aspnetcore2x 기본적으로 많은 코드가 있습니다. 준비, 리팩터링 만하면됩니다. 몇 가지 다른 경우가 있습니다. 특정 URL 경로에 도달했을 때만 인증 공급자를 해고하는 것 외에는 좋은 시작을 얻은 것 같습니다 ... 감사합니다! –