2017-01-20 9 views
0

우리는 우리 애플리케이션에 2 부분을 가지고 있습니다.SAML 인증 된 UI에서 AJAX API 호출을 인증합니다.

  • Jersey 2.0을 사용하여 다른 REST 엔드 포인트를 노출하는 Java 8로 작성된 백엔드.
  • React 및 다른 노드 모듈을 사용하여 작성된 단일 페이지 응용 프로그램 인 UI입니다.

웹 인터페이스는 Okta에서 지원하는 SAML 2.0 인증을 ID 공급자로 사용합니다. 백엔드는 HTTP 세션을 생성하고 JSESSIONID를 쿠키에 보냅니다.

이제 UI는 데이터를 표시하기 위해 REST 끝점을 호출합니다. 우리는 REST API에 인증 레이어를 추가해야하며 여기에 대해 별도의 질문을했습니다. Authenticating rest endpoints and the UI using Okta.

여기 내 질문은 특히 UI가 실제로 인증되고 HTTP 세션이 여전히 유효하기 때문에 이러한 API 호출에 대한 인증 수단으로 UI에서 전달할 수있는 것입니다. 따라서 별도의 OAuth 2.0 토큰을 UI에 전달해야 UI가이를 다시 백엔드로 전달할 수 있습니다. OAuth 2.0 흐름은 REST 엔드 포인트를 사용하는 외부 클라이언트에게 의미가 있습니다.

<!-- Authenticating REST APIs --> 
<security:http pattern="/rest/**" use-expressions="false"> 
    <security:intercept-url pattern="/nltools/**" access="IS_AUTHENTICATED_FULLY" /> 
    <security:custom-filter before="BASIC_AUTH_FILTER" ref="authValidationFilter" /> 
    <security:http-basic/> 
</security:http> 

<!-- SAML processing endpoints --> 
<security:http pattern="/saml/**" entry-point-ref="samlEntryPoint"> 
    <security:custom-filter before="FIRST" ref="metadataGeneratorFilter" /> 
    <security:custom-filter before="CSRF_FILTER" ref="samlFilter" /> 
    <security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter" /> 
</security:http> 

<!-- Secured pages with SAML as entry point --> 
<security:http entry-point-ref="samlEntryPoint" use-expressions="false"> 
    <security:csrf /> 
    <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" /> 
    <security:custom-filter before="FIRST" ref="metadataGeneratorFilter" /> 
</security:http> 

<security:authentication-manager alias="authenticationManager"> 
    <security:authentication-provider ref="httpBasicAuthenticationProvider" /> 
    <!-- Register authentication manager for SAML provider --> 
    <security:authentication-provider ref="samlAuthenticationProvider"/> 
    <!-- Register authentication manager for administration UI --> 
    <security:authentication-provider> 
     <security:user-service id="adminInterfaceService"> 
      <security:user name="admin" password="admin" authorities="ROLE_ADMIN"/> 
     </security:user-service> 
    </security:authentication-provider> 
</security:authentication-manager> 

내가 SecurityContextPersistenceFilter을 실행할 수있는 방법을 확실하지 않다 :

업데이트 1

이 모두 인증 체계를 정의 내 securityContext.xml의 발췌 한 것입니다. 내 /rest/** 패턴의 필터 중 하나를 재정의하고 추가해야합니까?

JS 코드 (반작용) 백엔드에 전화를 만드는 여기에 2

업데이트 :

return Promise.resolve().then(() => { 
 
     return request.post('/rest/v1/projects') 
 
     .send(data) 
 
     .then((success) => { 
 
      console.log('success!', success); 
 
      var projectName = success.body.name; 
 
      var projectId = success.body.id; 
 
      
 
      self.props.dispatch(projectActions.addNewProject(
 
      projectId, 
 
      projectName 
 
     )); 
 
     
 
      self.props.dispatch(appActions.displayGoodRequestMessage(projectName + " Saved")); 
 
      self.props.dispatch(projectActions.fetchProject(projectId)); 
 
      self.props.router.push('/projects'); 
 

 
     }

이제 JS 코드를 선택할 수 있습니다 모두를 보낼 수 이 도메인과 연관된 쿠키를 사용하여 백엔드에서 JSESSION ID 쿠키를 얻을 수 있지만 JS는 그렇게하지 않으며 그 일을 올바르게 수행 할 것이라고 생각하지 않습니다.

브라우저에서 https://mydomain/rest/v1/projects을 실행하면 로그인 한 상태에서 내 필터가 유효한 HTTP 세션을 검사 할 때 결과가 나타납니다. 요청에서 세션을 가져올 수 있기 때문에 결과가 나타납니다. request.getSession(false), JS가 API를 호출 할 때 이는 사실이 아닙니다. 완전히 다른 사용자 에이전트가됩니다.

업데이트 3 제안 당

@ 블라디미르 SCHAFER, 나는 특별한 아무것도 할 필요없이 .withCredentials()로 쿠키를 전송하고 백엔드 인증을 조금 위의 JS 코드를 변경할 수

return Promise.resolve().then(() => { 
 
     return request.post('/rest/v1/projects') 
 
     .withCredentials() 
 
     .send(data) 
 
     .then((success) => { 
 
      console.log('success!', success); 
 
      var projectName = success.body.name; 
 
      var projectId = success.body.id; 
 
      
 
      self.props.dispatch(projectActions.addNewProject(
 
      projectId, 
 
      projectName 
 
     )); 
 
     
 
      self.props.dispatch(appActions.displayGoodRequestMessage(projectName + " Saved")); 
 
      self.props.dispatch(projectActions.fetchProject(projectId)); 
 
      self.props.router.push('/projects'); 
 

 
     }

답변

2

만큼 REST API의 프런트 엔드가 인증에 사용하는 동일한 애플리케이션의 일부로서 Spring Security를 ​​사용하면 JSESSIONID에 액세스 할 수 있고 따라서 인증 된 사용자에 대한 모든 정보가 들어있는 Spring Security의 컨텍스트에 액세스하게된다. 따라서 추가 인증 메커니즘이 필요하지 않습니다.

당신이 필터 SecurityContextPersistenceFilter을 실행하면 사용자의 저지 호출을 처리 할 때, 당신이 사용하는 보안 컨텍스트에 액세스 할 수 있습니다 :

SecurityContextHolder.getContext().getAuthentication(); 

SecurityContextPersistenceFilter은의 인증 객체 저장을 가져 오기 위해 구성된 저장소를 사용합니다 SecurityContextHolder. 기본적으로 사용하는 HttpContextRepository을 살펴보십시오. 여기서 보안 컨텍스트가 저장되는 것은 SPRING_SECURITY_CONTEXT의 HttpSession이므로 직접 가져올 수도 있습니다.

물론 Spring 보안을 사용하여 프론트 엔드에서와 마찬가지로 REST API에서 인증 및 권한 부여를 수행 할 수 있습니다. 그러면 모든 것이 처리됩니다.

+0

내 securityContext.xml 발췌문을 사용하여 질문을 업데이트했습니다. SecurityContextPeristenceFilter를 실행할 때를 이해했는지 확신 할 수 없습니다. – user320599

+0

귀하의 질문에 스프링 시큐리티로 REST를 인증하지 않았다고 가정했습니다. 하지만 너는. REST 호출은 이미 인증을 요구하고 있으며 프론트 엔드는 JSESSIONID를 그대로 전송하며 더 이상 필요한 것은 없습니다. - 자신의 앱 외부에있는 제 3자가 REST API에 액세스 할 수있게하려는 경우가 아니면 (예 : OAuth 연극에 참여). –

+0

지금까지 입력 해 주셔서 감사합니다. 나는 REST API를 호출하는 Javascript 코드를 발췌하여 내 질문을 다시 업데이트했다. 요점은 앞으로 OAUTH2로 전환하고 싶을 때 REST 엔드 포인트를 외부에 노출시키고 싶습니다. – user320599