【问题标题】:Spring Security 3.0 : Basic Auth Prompt disappearSpring Security 3.0:基本身份验证提示消失
【发布时间】:2012-05-08 01:22:01
【问题描述】:

我在我的安全 xml 中使用带有以下设置的 spring 基本身份验证:

<http use-expressions="true" create-session="never" >
        <intercept-url pattern="/**" method="GET" access="isAuthenticated()" />
        <intercept-url pattern="/**" method="POST" access="isAuthenticated()" />
        <intercept-url pattern="/**" method="PUT" access="isAuthenticated()" />
        <intercept-url pattern="/**" method="DELETE" access="isAuthenticated()" />
        <http-basic />
    </http>

如果认证失败,浏览器会弹出提示窗口租用用户名和密码。 有什么办法让这个提示根本不弹出?

【问题讨论】:

    标签: spring spring-security basic-authentication


    【解决方案1】:

    最有可能用于身份验证失败的页面也受到保护。您可以尝试手动将失败页面设置为不受保护的页面,例如

     <access-denied-handler error-page="/login.jsp"/> 
    

    一起

     <intercept-url pattern="/*login*" access="hasRole('ROLE_ANONYMOUS')"/>
    

    <intercept-url pattern='/*login*' filters='none'/>  
    

    或者您可以使用 http 元素的 auto-config='true' 属性来解决此问题。查看更多 here

    【讨论】:

    • 谢谢@enterlezi。我尝试添加 filters='none' 并尝试将自动配置也添加到 http 元素,但它没有用。据我了解,提示是由于响应标题中的 WWW-Authenticate: Basic realm="Spring Security Application" 出现的。有没有办法修改响应的标头?
    • 我对标头一无所知,但我认为问题在于身份验证失败 url 仍然受到保护。尝试在您的 http 定义中添加一个 form-login 元素,例如 &lt;sec:form-login login-page="/login.jsp" login-processing-url="/login" authentication-failure-url="/login.jsp?error" default-target-url="/home.jsp"/&gt; 并替换为您的页面 (login.jsp)。还要确保使用 access="hasRole('ROLE_ANONYMOUS') 从过滤器中排除该页面,因为您已指定 use-expressions="true"
    • 问题是我没有开发客户端页面。我正在创建使用基本身份验证的其余 API。所以我真的没有任何失败的网址可以重定向到。你知道是否有一种方法可以让我在处理程序中捕获故障并在那里控制响应的标头?
    • 好的,现在有道理了。如果有帮助,请检查此答案stackoverflow.com/questions/4397062/…
    • 非常感谢。我已经像那个链接中的那个人一样调整了它,并且它有效。非常感谢你的帮助!非常感谢。
    【解决方案2】:

    浏览器中的 REST API 抛出登录对话框也有同样的问题。如您所说,当浏览器将响应标头视为

    WWW-Authenticate: Basic realm="Spring Security Application

    它将提示一个基本的身份验证对话框。对于基于 REST API 的登录,这并不理想。以下是我的做法。定义自定义身份验证入口点并在开始 将标题设置为“FormBased”

    response.setHeader("WWW-Authenticate", "FormBased");

    application-context.xml 配置如下

    <security:http create-session="never" entry-point-ref="authenticationEntryPoint" authentication-manager-ref="authenticationManager">
        <security:custom-filter ref="customRestFilter" position="BASIC_AUTH_FILTER" />
        <security:intercept-url pattern="/api/**" access="ROLE_USER" />
    </security:http>
    
    <bean id="authenticationEntryPoint" class="com.tito.demo.workflow.security.RestAuthenticationEntryPoint">
    </bean>
    

    自定义入口点类如下。

    @Component
    public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
    
        private static Logger logger = Logger.getLogger(RestAuthenticationEntryPoint.class);
    
        public void commence( HttpServletRequest request, HttpServletResponse response,
                              AuthenticationException authException ) throws IOException {
            logger.debug("<--- Inside authentication entry point --->");
            // this is very important for a REST based API login. 
            // WWW-Authenticate header should be set as FormBased , else browser will show login dialog with realm
            response.setHeader("WWW-Authenticate", "FormBased");
            response.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
        }
    
    
    }
    

    注意:我用的是spring 3.2.5.Release

    现在,当 POSTMAN 等 restclient 访问 rest API 时,服务器将返回 401 Unauthorized。

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题,我所做的是在我的资源服务器中创建一个自定义 RequestMatcher。这可以防止 Outh2 发送WWW-Authenticate header

      例子:

       @Override
      
          public void configure(HttpSecurity http) throws Exception {
               http.requestMatcher(new OAuthRequestedMatcher())
                      .authorizeRequests()
                       .antMatchers(HttpMethod.OPTIONS).permitAll()
                          .anyRequest().authenticated();
          }
      
          private static class OAuthRequestedMatcher implements RequestMatcher {
              public boolean matches(HttpServletRequest request) {
                  String auth = request.getHeader("Authorization");
                  boolean haveOauth2Token = (auth != null) && auth.startsWith("Bearer");
                  boolean haveAccessToken = request.getParameter("access_token")!=null;
         return haveOauth2Token || haveAccessToken;
              }
          }
      

      【讨论】:

        猜你喜欢
        • 2012-08-15
        • 2011-02-11
        • 2016-03-20
        • 1970-01-01
        • 2016-04-30
        • 2013-01-11
        • 2015-07-22
        • 2010-11-20
        • 2011-02-15
        相关资源
        最近更新 更多