2013-03-20 6 views
5

두 세트의 URL이 있습니다. 한 세트는 REST API이고, 두 번째 세트는 꽤 일반적인 웹 사이트입니다. 가끔씩 REST API를 호출하는 사용자/스크립트가 401 코드 (기본 인증은 괜찮을 수 있음) 또는 403에만 응답하도록 REST API에 대해 다른 보안 규칙을 적용하려고합니다.스프링 보안 - REST API 및 다른 URL에 대한 별도의 구성

그래서 허용하고 싶습니다. 다음에 대한 REST API 액세스 :

  • 로그인 한 사용자 (REST API를 호출하는 사이트 페이지의 javascript는 동일한 세션을 공유 함).
  • WWW-Authenticate 헤더에서 기본 인증 자격 증명으로 REST API를 호출하는 일부 스크립트.

현재 스프링이 내가 원하는 것을 "이해하게"만드는 구성을 파악하려고합니다. 나는 다음과 같은 설정 내놓았다 :

<beans:beans xmlns="http://www.springframework.org/schema/security" 
      xmlns:beans="http://www.springframework.org/schema/beans" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation=" 
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> 
    <http pattern="/" security="none" /> 
    <http pattern="/static/**" security="none" /> 

    <!-- REST API --> 
    <http pattern="/rest/*" use-expressions="true"> 
     <http-basic /> 
     <intercept-url pattern="/*" access="isAuthenticated()" /> 
    </http> 

    <!-- Site --> 
    <http access-denied-page="/WEB-INF/views/errors/403.jsp" use-expressions="true"> 
     <intercept-url pattern="/index.html" access="hasRole('ROLE_USER') or hasRole('ROLE_ANONYMOUS')" /> 
     <intercept-url pattern="/login.html" access="hasRole('ROLE_USER') or hasRole('ROLE_ANONYMOUS')" /> 
     <intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')" /> 
     <intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> 
     <form-login login-page="/login.html" 
        default-target-url="/index.html" 
        authentication-failure-url="/login.html?error=1" /> 

     <logout logout-url="/logout.do" logout-success-url="/index.html" /> 

     <anonymous username="guest" granted-authority="ROLE_ANONYMOUS" /> 
     <remember-me /> 
    </http> 

    <authentication-manager> 
     <authentication-provider> 
      <user-service> 
       <user name="admin" password="2" authorities="ROLE_ADMIN,ROLE_USER" /> 
       <user name="alex" password="1" authorities="ROLE_USER" /> 
      </user-service> 
     </authentication-provider> 
    </authentication-manager> 
</beans:beans> 

불행하게도뿐만 아니라 기본 인증이 설정 작동하지 않습니다하지만 거기에는 403 개 익명 사용자에 의해 요청에 대한 응답이 없습니다 - 찾을 수 리디렉션 (302)와 응용 프로그램이 응답하는 내가 좋겠 REST API URL을 허용하지 않으려면

<beans:bean id="ep403" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/> 


<!-- REST API --> 
<http pattern="/rest/*" entry-point-ref="ep403" use-expressions="true"> 
    <intercept-url pattern="/*" access="hasRole('ROLE_USER')" /> 
    <http-basic /> 
</http> 

을하지만이 중 하나가 작동하지 않습니다

나는 REST API에 대한 사용자 정의 진입 점을 추가했습니다.

내가하고 싶지 않은 것을 요약하면 :

  • 은 (인증 기능 계정으로 쿠키를 사용자 세션을해야) 권한이 부여 된 사용자가 REST API에 액세스 할 수 있도록 허용합니다.
  • 올바른 인증 토큰을 지정하고 쿠키에 세션을 지정하지 않으면 스크립트가 REST API에 액세스하도록 허용합니다.

UPDATE

봄 보안 내부로 파고 후 나는 특정 요청 또는하지를 거부할지 여부를 결정하는 코드를 발견했다. 이것은 소위 말하는 "Access Decision Voters"입니다. 기본적으로 모든 요청은 특정 요청에 적용되며 체인에있는 한 명의 액세스 결정 유권자가 특정 리소스에 대한 액세스를 거부하도록 투표하면 최종적으로 요청이 거부됩니다.

따라서 원래의 문제는 다음과 같은 방식으로 동작하는 특수 액세스 결정 투표자를 도입하여 해결할 수 있습니다. 세션에서 관련 역할을 추출하려고 시도하면 (요청에있는 경우)이 역할로 승인 단계로 진행합니다. 세션이 존재하지 않으면 WWW-Authenticate 헤더의 자격 증명에 대해 사용자를 인증하려고 시도한 다음 지정된 사용자와 관련된 역할로 인증 단계로 진행합니다.

답변

3

솔루션으로 파란색으로 재 게시 @ 제안 :) 희망이 도움이 될 것입니다.

간단한 해결책을 찾았습니다. 난 그냥 URL을 두 가지 세트 한 나머지 컨트롤러를 매핑 봄 보안 설정에 별개의 인증 처리기에 각 세트를 할당 :

<!-- Defines custom security policy for Stateful REST API --> 
<beans:bean id="nonRedirectingAccessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl"/> 
<beans:bean id="forbiddenEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/> 

<!-- Stateful REST API --> 
<http pattern="/rest/stateful/**" use-expressions="true" entry-point-ref="forbiddenEntryPoint"> 
    <access-denied-handler ref="nonRedirectingAccessDeniedHandler"/> 
    <intercept-url pattern="/rest/stateful/**" access="isAuthenticated()" /> 
</http> 

<!-- Stateless REST API --> 
<http pattern="/rest/stateless/**" use-expressions="true" create-session="stateless"> 
    <http-basic/> 
    <intercept-url pattern="/rest/stateless/**" access="isAuthenticated()" /> 
</http> 

그것은 미래에 당신이 할 수 있기 때문에 그 문제에 좋은 방법처럼 보인다 사용자 또는 스크립트 유스 케이스에 고유 한 고유 URL을 사용하여 "stateful"-user 또는 "stateless"-script REST API를 확장합니다.

내 경우에는 UX 변경시 특정 UI 시나리오를 구현하기 위해 설계된 몇 가지 새로운 메소드를 제공해야하며 일부 스크립트 시나리오는 일부 클라이언트 스크립트 - 서버 상호 작용을 지원하기 위해 일부 URL 만 추가해야 할 수도 있습니다.

0

는 REST API에 대한 pattern="/**"pattern="/rest/**"pattern="/*"pattern="/rest/*"을 변경하십시오 : 당신은 /rest/ 패턴을 갖는 URL을 확인하는 인터셉터를 사용할 수 있습니다

<http pattern="/rest/**" use-expressions="true"> 
    <intercept-url pattern="/**" access="isAuthenticated()" /> 
    <http-basic /> 
</http> 
+0

create-session이 트릭을 수행하지만, 기본 인증 작업을 세션별로 인증하지 못하게합니다. 즉, 페이지의 javascript가 REST API에 액세스 할 수 없습니다. – Alex

+0

네, 맞습니다. 패턴을 바꾸는 것이 도움이 되었습니까? –

+0

패턴에는 별다른 영향이 없습니다. 이제는 매우 간단한 REST API URL 스키마가 있습니다 (예 :/rest/book? name = X - 인증로드가 걸리면 확장 할 생각이 아닙니다) . 물론 내 패턴은/rest/one/two와 같이 깊은 네 스팅이있는 URL에서는 작동하지 않을 것이므로이를 지적 해 주셔서 감사합니다. create-session = "stateless"는 두 패턴 모두에 대해 기본적인 인증 작업을하지만 스프링이 두 패턴에 대해서도 기존의 인증 된 세션을 무시하게 만듭니다. – Alex

2

.이것은 XML의 헤더 부분에 아래 줄을 추가 들어

<mvc:interceptors> 
     <mvc:interceptor> 
      <mvc:mapping path="/rest/**"/> 
      <bean class="com.your.class.name.Interceptor></bean> 
     </mvc:interceptor> 
</mvc:interceptors> 

, 즉

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" 

이제 Interceptor 클래스 점검을 수행해야 무엇이든이 클래스는 봄 HandlerInterceptor 구현해야합니다.

public class Interceptor implements HandlerInterceptor{ 

    @Override 
    public boolean preHandle(HttpServletRequest request, 
          HttpServletResponse response, 
          Object handler) throws Exception { 
     //do what you need to check when the request arrives 
     //do authentications here 
     //return true if success 
     //else false 
    } 

    @Override 
    public void postHandle(HttpServletRequest request, 
          HttpServletResponse response, 
          Object handler, 
          ModelAndView modelAndView) throws Exception { 

    } 

    @Override 
    public void afterCompletion(HttpServletRequest request, 
           HttpServletResponse response, 
           Object handler, 
           Exception ex) throws Exception {  
    } 

} 

자세한 내용은 this을 참조하십시오. 도 볼 수 있습니다 this

+0

나는 너를 아주 잘 맞췄다 고 확신하지 못한다. 귀하의 접근 방식을 제대로 이해했다면 제안 된 요격기에 필요한 모든 인증 로직을 구현해야하므로 보안 구성이 security-context.xml과 맞춤형 인터셉터에 분산됩니다. 약간 무서워 보인다. 글쎄, 이것이 유일한 해결책이라면 REST URL에 대한 인증 및 권한 부여에 대한 나의 접근 방식을 다시 생각해보고 싶습니다. – Alex

+0

네, 그게 맞아요. 어떻게 당신이 권한을 currrently하고 있니? – Anubhab

+0

현재로드 밸런서 쪽에서 생각하고 있습니다. 이것은 매우 어렵고 깨지기 쉬운 접근 방법이지만, 작동합니다. 동시에이 문제에 대한 적절한 봄 보안 전용 솔루션을 적극적으로 찾고 있습니다. 기본 인증을 취소하고 REST API를 사용하는 스크립트에 별도의 로그인 URL을 포함하는 방식으로 내 접근 방식을 다시 생각해 볼 수 있습니다. – Alex