2013-02-06 44 views
21

Chúng tôi đang phát triển các dịch vụ web RESTful với Spring 3 và chúng tôi cần có chức năng đăng nhập/đăng xuất, chẳng hạn như /webservices/login/<username>/<password>//webservices/logout. Phiên phải được lưu trữ trong ngữ cảnh cho đến khi phiên hết hạn hoặc đăng xuất để cho phép tiêu thụ các dịch vụ web khác. Mọi yêu cầu truy cập dịch vụ web không có thông tin phiên nên bị từ chối. Tìm kiếm giải pháp tối tân cho kịch bản này.Đăng nhập/đăng xuất trong REST với Spring 3

Tôi thực sự đang hồi sinh câu hỏi được yêu cầu tại đây Spring Security 3 programmatically login, vẫn chưa được trả lời đúng cách. Vui lòng chỉ định các thay đổi cần thiết trong web.xml.

+7

Tôi thực sự khuyên bạn không nên đặt mật khẩu hoặc thậm chí tên người dùng trong URL. Những người nhận được đăng nhập bởi trung gian, được lưu trữ trong lịch sử, vv Thay vào đó, bạn sử dụng một cơ chế hiện có như HTTP cơ bản xác thực (qua SSL, tất nhiên). Đó sẽ là cách "RESTful": sử dụng khả năng của HTTP. (Tôi không thể nói với cách sử dụng Bảo mật Mùa xuân.) – dbreaux

+0

Hãy xem bài đăng này, nó mô tả cách dễ dàng cấu hình REST và xác thực thông thường bằng cách sử dụng Bảo mật Mùa xuân chuẩn. [Đăng nhập an ninh mùa xuân ajax] (http://stackoverflow.com/questions/4912485/spring-security-ajax-login/16577637#16577637) – SergeyB

Trả lời

50

Tôi khuyên bạn nên xác định bộ lọc bảo mật mùa xuân của mình theo cách thủ công hoàn toàn. Nó không phải là khó khăn, và bạn có toàn quyền kiểm soát hành vi đăng nhập/đăng xuất của bạn.

Trước hết, bạn sẽ cần lời giới thiệu web.xml tiêu chuẩn để ủy xử lý chuỗi bộ lọc để mùa xuân (loại bỏ async-hỗ trợ nếu bạn không sử dụng Servlet API ver 3):

<filter> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <async-supported>true</async-supported> 
    <filter-class> 
     org.springframework.web.filter.DelegatingFilterProxy 
    </filter-class> 
</filter> 



<filter-mapping> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

Bây giờ, trong an ninh ngữ cảnh, bạn sẽ xác định các bộ lọc riêng cho từng đường dẫn. Bộ lọc có thể xác thực người dùng, đăng xuất người dùng, kiểm tra thông tin đăng nhập bảo mật, v.v.

<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy"> 
    <sec:filter-chain-map path-type="ant"> 
     <sec:filter-chain pattern="/login" filters="sif,wsFilter"/> 
     <sec:filter-chain pattern="/logout" filters="sif,logoutFilter" /> 
     <sec:filter-chain pattern="/rest/**" filters="sif,fsi"/> 
    </sec:filter-chain-map> 
</bean> 

XML ở trên yêu cầu Spring chuyển yêu cầu đến URL tương đối ngữ cảnh cụ thể thông qua chuỗi bộ lọc. Điều đầu tiên trong bất kỳ chuỗi lọc nào là thiết lập bối cảnh bảo mật - 'sif' bean sẽ quan tâm đến điều đó.

<bean id="sif" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/> 

Bộ lọc tiếp theo trong chuỗi bây giờ có thể thêm dữ liệu vào ngữ cảnh bảo mật (đọc: đăng nhập/đăng xuất) hoặc quyết định có cho phép truy cập hay không.

Đối với URL đăng nhập của bạn, bạn sẽ muốn có một bộ lọc mà đọc dữ liệu xác thực từ yêu cầu, xác nhận nó, và trong các cửa hàng lần lượt nó trong bối cảnh an ninh (được lưu trữ trong phiên):

<bean id="wsFilter" class="my.own.security.AuthenticationFilter"> 
    <property name="authenticationManager" ref="authenticationManager"/> 
    <property name="authenticationSuccessHandler" ref="myAuthSuccessHandler"/> 
    <property name="passwordParameter" value="pass"></property> 
    <property name="usernameParameter" value="user"></property> 
    <property name="postOnly" value="false"></property> 

Bạn có thể sử dụng Spring generic UsernamePasswordAuthenticationFilter nhưng lý do tôi sử dụng triển khai của riêng mình là tiếp tục lọc chuỗi xử lý (thực thi mặc định giả định người dùng sẽ được chuyển hướng đến auth thành công và chấm dứt chuỗi bộ lọc) , Và có thể xử lý xác thực mỗi tên đăng nhập và mật khẩu thời gian được truyền cho nó:

public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter { 

@Override 
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) { 
    return (StringUtils.hasText(obtainUsername(request)) && StringUtils.hasText(obtainPassword(request))); 
} 

@Override 
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, 
     Authentication authResult) throws IOException, ServletException{ 
    super.successfulAuthentication(request, response, chain, authResult); 
    chain.doFilter(request, response); 
} 

Bạn có thể thêm bất kỳ số lượng hiện thực của riêng bộ lọc cho path/đăng nhập, chẳng hạn như xác thực sử dụng tiêu đề HTTP auth cơ bản, tiêu hóa tiêu đề hoặc thậm chí trích xuất tên người dùng/pwd từ phần thân yêu cầu. Spring cung cấp một loạt các bộ lọc cho điều đó.

tôi có riêng handler auth thành công của tôi ai sẽ ghi đè các chiến lược chuyển hướng mặc định:

public class AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { 

    @PostConstruct 
    public void afterPropertiesSet() { 
     setRedirectStrategy(new NoRedirectStrategy()); 
    } 

    protected class NoRedirectStrategy implements RedirectStrategy { 

     @Override 
     public void sendRedirect(HttpServletRequest request, 
       HttpServletResponse response, String url) throws IOException { 
      // no redirect 

     } 

    } 

} 

Bạn không cần phải có xử lý thành công tùy chỉnh auth (và bộ lọc có thể tùy chỉnh auth cũng) nếu bạn là ok với người dùng được chuyển hướng sau khi đăng nhập thành công (URL chuyển hướng có thể được tùy chỉnh, tài liệu kiểm tra)

xác định giám đốc thẩm những người sẽ chịu trách nhiệm để lấy thông tin chi tiết của người dùng:

<sec:authentication-manager alias="authenticationManager"> 
    <sec:authentication-provider ref="myAuthAuthProvider"/> 
</sec:authentication-manager> 

<bean id="myAuthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider"> 
    <property name="preAuthenticatedUserDetailsService"> 
     <bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper"> 
      <property name="userDetailsService" ref="myUserDetailsImpl"/> 
     </bean> 
    </property> 
</bean> 

Bạn sẽ phải cung cấp thông tin chi tiết về người dùng của riêng bạn tại đây.

lọc Thoát: chịu trách nhiệm thanh toán bù trừ bối cảnh an ninh

<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"> 
    <constructor-arg> 
     <list> 
      <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/> 
     </list> 
    </constructor-arg> 
</bean> 

Generic thứ xác thực:

<bean id="httpRequestAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"> 
    <property name="allowIfAllAbstainDecisions" value="false"/> 
    <property name="decisionVoters"> 
     <list> 
      <ref bean="roleVoter"/> 
     </list> 
    </property> 
</bean> 

<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter"/> 

<bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter"/> 

lọc kiểm soát truy cập (nên được tự giải thích):

<bean id="fsi" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> 
    <property name="authenticationManager" ref="myAuthenticationManager"/> 
    <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/> 
    <property name="securityMetadataSource"> 
     <sec:filter-invocation-definition-source> 
      <sec:intercept-url pattern="/rest/**" access="ROLE_REST"/> 
     </sec:filter-invocation-definition-source> 
    </property> 
</bean> 

Bạn nên cũng có thể bảo mật các dịch vụ REST của bạn với @Secured một chú thích về phương pháp.

Ngữ cảnh ở trên được lấy từ ứng dụng web dịch vụ REST hiện có - xin lỗi vì bất kỳ lỗi chính tả nào có thể xảy ra. Bạn cũng có thể thực hiện ít nhất hầu hết những gì được triển khai ở đây bằng cách sử dụng các thẻ Spring sec Spring, nhưng tôi thích cách tiếp cận tùy chỉnh hơn vì điều đó giúp tôi kiểm soát nhiều nhất.

Hy vọng điều này ít nhất sẽ giúp bạn bắt đầu.

+1

Cảm ơn bạn rất nhiều vì câu trả lời thuyết phục và chi tiết này. – FKhan

+0

Làm cách nào bạn gọi URL đăng xuất để đăng xuất người dùng? – Franklin

+1

@Franklin, lưu ý các định nghĩa đường dẫn trên springSecurityFilterChain bean: đường dẫn/logout được thiết lập để gọi logoutFilter, điều này sẽ xóa bối cảnh bảo mật và đăng xuất người dùng – rootkit

Các vấn đề liên quan