java 使用 Spring Security 的同一应用程序中的两个领域?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3671861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 02:56:58  来源:igfitidea点击:

Two realms in same application with Spring Security?

javaspringsecurityspring-security

提问by Marcel St?r

We're building a web application that is available to both authenticated and anonymous users. If you decide not to register/login you only have a limited set of features. User authentication is done over OpenID with Spring Security. That works fine.

我们正在构建一个可供经过身份验证的用户和匿名用户使用的 Web 应用程序。如果您决定不注册/登录,您只能使用有限的一组功能。用户身份验证是通过 OpenID 使用 Spring Security 完成的。这很好用。

However, the application also comes with an admin UI that is deployed at <host>/<context-root>/admin. Can we have two separate realms with Spring Security (e.g. basic auth for /admin/**)? How does that have to be configured?

但是,该应用程序还带有一个部署在<host>/<context-root>/admin. 我们可以使用 Spring Security 拥有两个独立的领域(例如,基本身份验证/admin/**)吗?那必须如何配置?

回答by gutch

Spring Security has added support for this scenario in version 3.1, which is currently available as a Release Candidate. It was implemented by SEC-1171and details of the syntax are in the manual included with 3.1.

Spring Security 在版本 3.1 中添加了对这种场景的支持,该版本目前可作为候选发布版本。它是由SEC-1171实现的,语法的详细信息在 3.1 附带的手册中。

However it's pretty simple to use. Basically you just define multiple httpelements in your Spring Security configuration, one for each realm. We're using it like this:

但是它使用起来非常简单。基本上,您只需http在 Spring Security 配置中定义多个元素,每个领域一个。我们像这样使用它:

<!-- Configure realm for system administration users -->
<security:http pattern="/admin/**" create-session="stateless">
    <security:intercept-url pattern='/**' access='ROLE_ADMIN' requires-channel="https" />
    <security:http-basic/>  
</security:http>


<!-- Configure realm for standard users -->
<security:http auto-config="true" access-denied-page="/error/noaccess" use-expressions="true" create-session="ifRequired">
    <security:form-login login-page="/login"
            ...
            ...
</security:http>

The key thing to note is the pattern="/admin/**"on the first httpelement. This tells Spring that all URLs under /adminare subject to that realm instead of the default realm — and thus URLs under /adminuse basic authentication instead.

要注意的关键是pattern="/admin/**"第一个http元素上的 。这告诉 Spring 下的所有 URL/admin都受该领域而不是默认领域的约束——因此下的 URL/admin使用基本身份验证。

回答by Boris Kirzner

Possible solution:

可能的解决方案:

  • Add URL interceptor for /adminthe requires "ROLE_ADMIN"
  • Configure instance of org.springframework.security.web.authentication.www.BasicAuthenticationFilterto intercept the /adminURL and authenticate user as ROLE_ADMIN if it provides the appropriate credentials
  • /admin需要“ROLE_ADMIN”添加 URL 拦截器
  • 配置实例org.springframework.security.web.authentication.www.BasicAuthenticationFilter以拦截/adminURL 并将用户身份验证为 ROLE_ADMIN 如果它提供适当的凭据

Sample configuration:

示例配置:

<security:intercept-url pattern="/admin" access="ROLE_ADMIN"/>

<bean id="basicAuthenticationEntryPoint" 
      class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
    <property name="realmName" 
              value="WS realm"/>
</bean>

<bean id="basicAuthenticationProcessingFilter"
      class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
    <property name="authenticationManager" 
              ref="authenticationManager"/>
    <property name="authenticationEntryPoint" 
              ref="basicAuthenticationEntryPoint"/>    
</bean>

Note: default implementation of BasicAuthenticationFilter is a passive filter, i.e. it just looks for a basic auth header in the request and if it is not present - does nothing. If you want the filter to explicitly require the basic authentication from the client, you need to extend the default implementation to commence to authentication entry point:

注意:BasicAuthenticationFilter 的默认实现是一个被动过滤器,即它只是在请求中寻找一个基本的 auth 标头,如果它不存在 - 什么都不做。如果您希望过滤器明确要求来自客户端的基本身份验证,则需要扩展默认实现以开始身份验证入口点:

public class BasicAuthenticationFilter 
       extends org.springframework.security.web.authentication.www.BasicAuthenticationFilter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        final HttpServletRequest request = (HttpServletRequest) req;
        final HttpServletResponse response = (HttpServletResponse) res;

        String header = request.getHeader("Authorization");

        if ((header != null) && header.startsWith("Basic ")) {
            super.doFilter(req, res, chain);
        } else {
            getAuthenticationEntryPoint().commence(request, response, new AuthenticationCredentialsNotFoundException("Missing credentials"));
        }
    }
}

In addition, you need to tweak the filter to apply to /adminURL only - either by hard-coding this in doFiltermethod or by providing an appropriate wrapper bean.

此外,您需要调整过滤器以仅应用于/adminURL - 通过在doFilter方法中对此进行硬编码或通过提供适当的包装 bean。

回答by dube

I can't think of a straight forward way to have two realms (and I didn't try it myself):

我想不出有两个领域的直接方法(我自己也没有尝试过):

you may define two filters in your web.xmlwhere each of those has a different spring configuration and ergo an own environment. The global things go into the app config, the realm-specific in the filter config.

您可以在您的 web.xml中定义两个过滤器其中每个过滤器都有不同的 spring 配置并因此有自己的环境。全局事物进入应用程序配置,过滤器配置中特定于领域的内容。

if it's only for a different auth method, you could write your own filterwhich then decides which filter to call.

如果它仅用于不同的身份验证方法,您可以编写自己的过滤器,然后决定调用哪个过滤器。