2017-04-03 3 views
1

WebAPIMVC5/Web Api 2으로 설정하려고하는데 현재 현재 기본 구성과 다른 기본값을 사용하고 있습니다. 브라우저에서 계정으로 로그인 할 때 홈 페이지가 승인 될 때처럼 표시되는 것처럼 [Authorize] 속성을 사용하여 정상적인 MVC 컨트롤러 동작을 수행 할 수 있습니다. 그런 다음 /api/Me (기본 내장 메모리) API 컨트롤러 액션) 또는 사용자 정의 API를 컨트롤러 액션에 I 인증을 요구하는 기본 MVC 웹 API 2 비계로 만든 것, 나는 오류과 같이 얻을 :WebAPI 로그인 할 때 오류가 반환됩니다.

{"message":"Authorization has been denied for this request."} 

이것은 내가 그것을 시도하고있을 때입니다 Microsoft Edge, 아직 구축중인 실제 클라이언트 코드에서 시도하지 않았습니다. 이는 UWP 앱입니다. 먼저 브라우저에서 테스트하여 문제가 제대로 작동하는지 확인했습니다.

나는이 기사를보기 시작했다 : https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/individual-accounts-in-web-api 그것은 요구 및 SPAs에 더 많은 기어 배치되는 것을 보인다. 내 목표는 웹을 통해 작업하고 있고 UWP을 통해 작업하는 것입니다. 앱이 인트라넷에서 실행되고 웹 API를 실행하는 인트라넷 IIS 서버에 액세스하므로 UWP의 데스크톱 클라이언트를 구축하고 싶기 때문에 더 많은 시간을 UWP쪽에 집중할 것입니다. 결국 Xamarin은 Web API를 통해 데이터에 액세스합니다.

Edge와 같은 일반 웹 브라우저를 사용하는 경우 [Authorize] 속성을 통해 보안 될 때 웹 API 컨트롤러 작업에 액세스 할 수 없다고 가정하는 것이 안전합니까? 머리글?

+0

음 John, 고객의 승인 토큰을 고객의 승인 된 조치로 어떻게 보냅니 까? MVC 또는 UWP 또는 Javascript 클라이언트와 상관없이 HttpClient (MVC, UWP)를 사용하여 API에 Authorization 헤더의 토큰을 보내거나 자바 클라이언트 인 경우 ajax, jquery 등을 사용하여 클라이언트를 지정해야합니다. – Jinish

+0

인증 된 끝점을 테스트 할 수 있습니다 우편 배달부 또는 Fiddler와 같은 프록시 도구를 사용하여 요청을 만들 때 여기에 토큰과 함께 Authorization 헤더를 추가하십시오. – Jinish

+0

그래서 지금 내 UWP 앱에서/Account/Login에서 GET을 수행하여 페이지를 먼저 얻습니다. 안티 위조 토큰을 얻을 수 있습니다. 잘못된 장소에서 찾고 있지 않는 한 UWP에서 HTML DOM 라이브러리를 찾는 데 어려움이 있으므로 정규 표현식을 통해 구문 분석하고 있습니다 (타사는 사용하지 않음). 그 시점에서 나는 여전히 Authorize를 사용하여 Web API를 사용한다고 가정하는 베어러 토큰을 얻고 싶습니다. 아직 어떻게해야 할 지 잘 모르겠습니다. –

답변

2

UWP 앱에서 다음과 같은 몇 가지 방법을 만들거나 DI (선택 사항)를 통해 주입 할 수있는 클래스로 래핑 할 수 있습니다.

public async Task<TResult> GetAsync<TResult>(string uriString) where TResult : class 
    { 
     var uri = new Uri(uriString); 
     using (var client = GetHttpClient()) 
     { 
      HttpResponseMessage response = await client.GetAsync(uri); 
      if (response.StatusCode != HttpStatusCode.OK) 
      { 
       //Log.Error(response.ReasonPhrase); 
       return default(TResult); 
      } 
      var json = await response.Content.ReadAsStringAsync(); 
      return JsonConvert.DeserializeObject<TResult>(json, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); 
     } 
    } 

    public async Task<TResult> PostAsync<TResult, TInput>(string uriString, TInput payload = null) where TInput : class 
    { 
     var uri = new Uri(uriString); 
     using (var client = GetHttpClient()) 
     { 
      var jsonContent = JsonConvert.SerializeObject(payload, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); 
      HttpResponseMessage response = await client.PostAsync(uri, new StringContent(jsonContent, Encoding.UTF8, "application/json")); 
      if (response.StatusCode != HttpStatusCode.OK) 
      { 
       //Log.Error(response.ReasonPhrase); 
       return default(TResult); 
      } 
      var json = await response.Content.ReadAsStringAsync(); 
      return JsonConvert.DeserializeObject<TResult>(json); 
     } 
    } 

그리고 당신은 기본 (사용자 이름 및 암호 인증)를 사용하는 경우 다음 GetHttpClient 방법이 될 것입니다 뭔가 같은 :

private HttpClient GetHttpClient() 
    { 
     var client = new HttpClient(); 
     var username = // get username; 
     var password = // get password; 
     client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"))); 
     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
     return client; 
    } 

또는 토큰 다음 베어러를 사용하는 경우 당신이 할 수 있습니다 :

client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer ", "string token goes here..."); 
+0

나는이 코드를 UWP 플랫폼에서 테스트하지 않았지만 HttpClient 클래스에 액세스 할 수 있다고 확신한다. 그래서 비슷한 선상에서 뭔가를 할 수 있습니다. 적절한 클래스를 찾아야 할 수도 있습니다. – Jinish

+0

감사합니다. 그래도 토큰을받는 데 문제가 있습니다. 그래서 우편 배달부에서 사용자 이름과 암호를 사용하여 POST에서 http : // localhost : 55970/Token을 가리키고이 글에서 언급 한 grant_type = "password"를 x-www-form-urlencoded로 지정하려고합니다. { "error": "invalid_client"}와 함께 json을 다시 얻습니다. 클라이언트를 인식하도록 설정해야하는지 잘 모르겠습니다. –

+0

늦게 답장을 드려 죄송합니다. 오히려 바빴다. 인증 공급자 코드를 디버깅하려고 시도 했습니까? – Jinish

0

UWP 또는 Xamarin과 같은 클라이언트에서 MVC5/Web API 2에 액세스하려는이 문제로 어려움을 겪고있는 사람을 위해 여기에 약간의 보충 정보를 게시합니다. Authorize 속성으로 웹 API의 영역을 잠글 필요가 있습니다.

상위 수준 프로세스는 MVC 컨트롤러를 거치지 않고/Token 끝점 (또는 지정된 끝점)에 직접 POST를 수행하는 것입니다.

우선 최초의, 당신은 개발을위한 SSL을하고 싶지만 아직 인증서가없는 경우, 가서 다음 실행 : 55970는 어떤 지역의 웹 사이트 포트의 포트입니다

C:\Program Files (x86)\IIS Express>iisexpressadmincmd setupSslUrl -url:https://localhost:55970/ -UseSelfSigned 

을 나는 이것을 본문에서 언급 할 것이다.

다음 작업은 클라이언트 유효성 검사 및 리소스 부여 메서드에서 ApplicationOAuthProvider.cs를 무시하고 유효하지 않은 클라이언트 또는 유효하지 않은 권한 부여 오류로 실행합니다.

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
    { 
     context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); 

     UserManager<ApplicationUser> _userManager; 
     ApplicationDbContext db = new ApplicationDbContext(); 
     _userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db)); 
     try 
     { 

      ApplicationUser user = await _userManager.FindAsync(context.UserName, context.Password); 


      if (user == null) 
      { 
       context.SetError("invalid_grant", "The user name or password is incorrect."); 
       return; 
      } 

      var identity = new ClaimsIdentity(context.Options.AuthenticationType); 
      identity.AddClaim(new Claim("sub", context.UserName)); 
      identity.AddClaim(new Claim("role", "user")); 

      context.Validated(identity); 
     } 
     catch (Exception ex) 
     { 
      string str = ex.ToString(); 
     } 

     db.Dispose(); 
    } 

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 
    { 
     string clientId = ""; 
     string clientSecret = ""; 
     context.TryGetFormCredentials(out clientId, out clientSecret); 

     List<string> validClients = new List<string>(){ "web","Alliance_UWP","Alliance_Xamarin","Alliance_Web" }; 
     if (validClients.Contains(clientId)) 
      context.Validated(); 
    } 

당신은 내가 허용 된 클라이언트에서 인 것처럼 자세한 될 필요가 없습니다, 그냥 "웹"괜찮습니다, 당신은 함께, URL 인코딩 형식 값으로 당신의 HTTP POST 방법에 그것을 포함합니다 grant_type = "password"및 사용자 이름/암호. 다음은 사용자 이름/비밀번호를 가져와 Authorize 속성으로 묶인 API를 통해 가져온 데이터 세트에 액세스하는 빠르고 간단한 UWP 클라이언트입니다. 인증을하지 않으면 인증 오류가 발생합니다. 이는 우리가 원하는 것입니다.

위의 명령을 통해 IIS Express에서 자체 서명 된 인증서를 설정 했으므로 클라이언트에서 자체 서명 된 인증서 오류를 필터링한다는 점을 기억하십시오.

Uri tokenUri = new Uri(@"https://localhost:55970/Token"); 
    // This is a test data set from my Web Api pulling data from 
    // Entity Framework and SQL Server protected by the Authorize attribute 
    Uri testCasesUri = new Uri(@"https://localhost:55970/api/Cases"); 
    string accessToken = ""; 

    public MainPage() 
    { 
     this.InitializeComponent(); 
    } 

    private async void btn_SubmitLogin_Click(object sender, RoutedEventArgs e) 
    { 
     string username = txt_User.Text; 
     string password = txt_Password.Password; 

     HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter(); 
     filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted); 
     filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName); 
     filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationFailure); 
     HttpClient client = new HttpClient(filter); 
     Dictionary<string, string> parameters = new Dictionary<string, string>(); 
     parameters.Add("client_id", "web"); 
     parameters.Add("grant_type", "password"); 
     parameters.Add("username", username); 
     parameters.Add("password", password); 
     try 
     { 
      HttpResponseMessage result = await client.PostAsync(tokenUri, new HttpFormUrlEncodedContent(parameters)); 
      string jsonResult = await result.Content.ReadAsStringAsync(); 
      // TokenResult is a custom model class for deserialization of the Token Endpoint 
      // Be sure to include Newtonsoft.Json from NuGet 
      var resultObject = JsonConvert.DeserializeObject<TokenResult>(jsonResult); 
      accessToken = resultObject.AccessToken; 

      // When setting the request for data from Web Api set the Authorization 
      // header to Bearer and the token you retrieved 
      client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken); 
      result = await client.GetAsync(testCasesUri); 
      jsonResult = await result.Content.ReadAsStringAsync(); 

     } catch(Exception ex) 
     { 
      string debugBreak = ex.ToString(); 
     } 

웹 API를 사용하는 Xamarin 또는 UWP를 사용하는 데 문제가있는 사용자에게 도움이 될 수있는 희망입니다.

관련 문제