Spring security for both web services and users

2019-03-05 23:50发布

问题:

We have a web application, and we're want to use spring security to secure it in 2 different ways:

1) Users that are authenticate using login form and have access to certain services.

2) Other services that are secured using digest authentication (user + password are passed in the request's header) - used by other webapps so there's no login form.

Each of these works on it's own, but we weren't able to get them to work in the same web app. When we try to run a webapp with both xmls we get the following error:

A universal match pattern ('/**') is defined  before other patterns in the filter chain, causing them to be ignored. Please check the ordering in your <security:http> namespace or FilterChainProxy bean configuration

The security.xml for users:

<security:http use-expressions="true">
    <security:intercept-url pattern="/user/login"
        access="permitAll" />
    ...
    <security:intercept-url pattern="/**"
        access="isAuthenticated()" />

    <security:form-login
        authentication-success-handler-ref="userAuthenticationSuccessHandler" />

    <security:logout logout-url="/user/logout"
        logout-success-url="/demo/user/logoutSuccess" />
</security:http>

<bean id="bCryptPasswordEncoder"
    class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

<security:authentication-manager alias="authenticationManager">
    <security:authentication-provider
        ref="authenticationProvider">
    </security:authentication-provider>
</security:authentication-manager>

The rest-security.xml for web services:

<security:http create-session="stateless"
    entry-point-ref="digestEntryPoint">
    <security:intercept-url pattern="/provider/**"
        access="ROLE_WEBAPP" />

    <security:http-basic />
    <security:custom-filter ref="digestFilter"
        after="BASIC_AUTH_FILTER" />
</security:http>

<bean id="digestFilter"
    class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
    <property name="userDetailsService" ref="webappDetailsServiceImpl" />
    <property name="authenticationEntryPoint" ref="digestEntryPoint" />
</bean>

<bean id="digestEntryPoint"
    class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
    <property name="realmName" value="Contacts Realm via Digest Authentication" />
    <property name="key" value="acegi" />
</bean>

<security:authentication-manager>
    <security:authentication-provider
        ref="restAuthenticationProvider">
    </security:authentication-provider>
</security:authentication-manager>

Does anyone has experiences with this kind of scenario?

回答1:

I found the solution here: https://blog.codecentric.de/en/2012/07/spring-security-two-security-realms-in-one-application/

This post details exactly what I wanted to do.

The trick seems to be adding pattern="/provider/**" to the rest http element. So the correct rest-security configuration is:

<security:http create-session="stateless"
    entry-point-ref="digestEntryPoint" pattern="/provider/**"
    use-expressions="true">
    <security:intercept-url pattern="/provider/**"
        access="isAuthenticated()" />

    <security:http-basic />
    <security:custom-filter ref="digestFilter"
        after="BASIC_AUTH_FILTER" />
</security:http>


回答2:

This might not be quite what you're looking for, but I would consider breaking the two apis apart. One for humans and one for web services.

We have our human interface right off the root context:

http(s)://your.website.com/...

We then have our web service interface off of the api context:

http(s)://your.website.com/api/v1/...

This makes it easy to handle the two different types of security you're looking for with spring.



回答3:

The error message

A universal match pattern is defined before other patterns in the filter chain, causing them to be ignored.

is very concise.

You should check the order of bean definition files of your contextConfigLocation context parameter in your web.xml.

<context-param>  
    <param-name>contextConfigLocation</param-name>  
    <param-value>security.xml,rest-security.xml</param-value>  
</context-param>

should reproduce the above error message.

<context-param>  
    <param-name>contextConfigLocation</param-name>  
    <param-value>rest-security.xml,security.xml</param-value>  
</context-param>

should solve the issue.