处理Spring Security中基本身份验证的未经授权的错误消息 [英] Handle unauthorized error message for Basic Authentication in Spring Security

查看:146
本文介绍了处理Spring Security中基本身份验证的未经授权的错误消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的Web应用程序中使用Spring Security 3.0.5。基本上,我想要一个通过 HTTP GET 以json格式返回数据的Web服务。



我已经实现了RESTful服务,在请求url http:// localhost:8080 / webapp / json 时返回数据。这适用于以下curl命令

 > curl http:// localhost:8080 / webapp / json 
{key:values}

使用spring security添加基本身份验证后,我可以使用以下命令获取数据

 > curl http:// localhost:8080 / webapp / json 
< html>< head>< title> Apache Tomcat / 6.0.29 - 错误报告.....
> curl -u用户名:密码http:// localhost:8080 / webapp / json
{key:values}

前一个命令返回标准的tomcat错误页面,因为它现在需要用户名和密码。 我的问题是,是否可以以打印出我自己的错误消息的方式处理拒绝访问?

 > curl http:// localhost:8080 / webapp / json 
{error:401,message:需要用户名和密码}

这是我的spring安全配置和 AccessDeniedHandler 。正如您所看到的,我正在尝试添加 access-denied-handler ,它只是通过servlet响应打印出一个字符串,但它仍然不会在命令行上打印我自己的消息。

 <?xml version =1.0encoding =UTF-8?> 
< 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
xmlns:context =http://www.springframework.org/schema/context
xmlns:p =http://www.springframework.org/schema/p
xsi:schemaLocation =http://www.springframework.org/schema/beans http://www.springframework。 org / schema / beans / spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0。 xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd\">
< global-method-security secured-annotations =enabled/>

< beans:bean name =access-deniedclass =webapp.error.JSONAccessDeniedHandler>< / beans:bean>

< http auto-config =true>
< access-denied-handler ref =access-denied/>
< intercept-url pattern =/ jsonaccess =ROLE_USER,ROLE_ADMIN/>
< http-basic />
< / http>

< authentication-manager>
< authentication-provider>
< password-encoder hash =md5/>
< user-service>
...
< / user-service>
< / authentication-provider>
< / authentication-manager>

< / beans:beans>

AccessDeniedHandler.java

  package webapp.error; 

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

公共类JSONAccessDeniedHandler实现AccessDeniedHandler {

@Override
public void handle(HttpServletRequest请求,HttpServletResponse响应,AccessDeniedException accessDeniedException)抛出IOException,ServletException {
PrintWriter writer = response.getWriter();
writer.print({\error \:\401 \,\message \:\所需的用户名和密码\});
}

}


解决方案

我已经解决了我的问题所以我想我应该在这里分享。此配置允许服务器根据请求软件以不同方式发送错误消息。如果请求来自Web浏览器,它将检查 User-Agent 标头,并在必要时重定向到表单登录。如果请求来自,例如, curl ,它将在身份验证失败时打印出纯文本错误消息。



< pre class =lang-xml prettyprint-override> <?xml version =1.0encoding =UTF-8?>
< beans
xmlns =http://www.springframework.org/schema/beans
xmlns:sec =http://www.springframework.org/schema/security
xmlns:xsi =http://www.w3.org/2001/XMLSchema-instance
xmlns:context =http://www.springframework.org/schema/context
xmlns:p =http://www.springframework.org/schema/p
xsi:schemaLocation =
http://www.springframework.org/schema/beans http: //www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/ spring-context-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd\">

<! - AspectJ切入点表达式,它定位我们的post方法并以
< protect-pointcut expression =执行(* bigbank。* Service.post *)的方式应用安全性(..))access =ROLE_TELLER/> - >
< sec:global-method-security secured-annotations =enabled/>

< bean id =basicAuthenticationFilter
class =org.springframework.security.web.authentication.www.BasicAuthenticationFilter
p:authenticationManager-ref =authenticationManager
p:authenticationEntryPoint-ref =basicAuthenticationEntryPoint/>

< bean id =basicAuthenticationEntryPoint
class =webapp.PlainTextBasicAuthenticationEntryPoint
p:realmName =myWebapp/>

< bean id =formAuthenticationEntryPoint
class =org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
p:loginFormUrl =/ login.jsp/> ;

< bean id =daepclass =org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint>
< constructor-arg>
< map>
< entry key =hasHeader('User-Agent','Mozilla')或hasHeader('User-Agent','Opera')或hasHeader('User-Agent','Explorer')value -ref =formAuthenticationEntryPoint/>
< / map>
< / constructor-arg>
< property name =defaultEntryPointref =basicAuthenticationEntryPoint/>
< / bean>

< sec:http entry-point-ref =daep>
< sec:intercept-url pattern =/ login.jsp *filters =none/>
< sec:intercept-url pattern =/ jsonaccess =ROLE_USER,ROLE_ADMIN/>
< sec:intercept-url pattern =/ json / *access =ROLE_USER,ROLE_ADMIN/>
< sec:logout
logout-url =/ logout
logout-success-url =/ home.jsp/>
< sec:form-login
login-page =/ login.jsp
login-processing-url =/ login
authentication-failure-url = /login.jsp?login_error=1default-target-url =/ home.jsp/>
< sec:custom-filter position =BASIC_AUTH_FILTERref =basicAuthenticationFilter/>
< / sec:http>

< sec:authentication-manager alias =authenticationManager>
< sec:authentication-provider>
...
< / sec:authentication-provider>
< / sec:authentication-manager>

< / beans>

PlainTextBasicAuthenticationEntryPoint 扩展 org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint

  import java.io. IOException异常; 
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;

公共类PlainTextBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

@Override
public void starts(HttpServletRequest request,HttpServletResponse response,AuthenticationException authException)抛出IOException,ServletException {
response.addHeader(WWW-Authenticate,Basic realm = \+ getRealmName()+\);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter writer = response.getWriter();
writer.println(HTTP Status+ HttpServletResponse.SC_UNAUTHORIZED + - + authException.getMessage());
}
}


I am trying to use Spring Security 3.0.5 in my web application. Basically, I want to have a web service which return data in json format via HTTP GET.

I have implemented a RESTful service which returns data when the url http://localhost:8080/webapp/json is requested. This works fine with the following curl command

> curl http://localhost:8080/webapp/json
{"key":"values"}

After I added basic authentication using spring security, I can use following commands to get the data

> curl  http://localhost:8080/webapp/json
<html><head><title>Apache Tomcat/6.0.29 - Error report .....
> curl -u username:password http://localhost:8080/webapp/json
{"key":"values"}

The former command returns standard tomcat error page since now it requires username and password. My question is whether it is possible to handle access denied in such a way that it prints out my own error message? i.e.

> curl  http://localhost:8080/webapp/json
{"error":"401", "message":"Username and password required"}

Here is my spring security configuration and AccessDeniedHandler. As you can see, I am trying to add access-denied-handler which simply prints out a string through servlet response but it still does not print my own message on command line.

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
          http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
    <global-method-security secured-annotations="enabled"/>

    <beans:bean name="access-denied" class="webapp.error.JSONAccessDeniedHandler"></beans:bean>

    <http auto-config="true">
        <access-denied-handler ref="access-denied"/>
        <intercept-url pattern="/json" access="ROLE_USER,ROLE_ADMIN"  />
        <http-basic />
    </http>

    <authentication-manager>
        <authentication-provider>
            <password-encoder hash="md5"/>
            <user-service>
            ...
            </user-service>
        </authentication-provider>
    </authentication-manager>

</beans:beans>

AccessDeniedHandler.java

package webapp.error;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

public class JSONAccessDeniedHandler implements AccessDeniedHandler  {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        PrintWriter writer = response.getWriter();
        writer.print("{\"error\":\"401\", \"message\":\"Username and password required\"}");
    }

}

解决方案

I have solved my problem so I think I should share it here. This configuration allows server to send out error message differently depending on the requesting software. If the request comes from a web browser, it will check the User-Agent header and redirect to a form login if necessary. If the request comes from, for example, curl, it will print out plain text error message when the authentication fails.

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:sec="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <!-- AspectJ pointcut expression that locates our "post" method and applies security that way
    <protect-pointcut expression="execution(* bigbank.*Service.post*(..))" access="ROLE_TELLER"/>-->
    <sec:global-method-security secured-annotations="enabled"/>

    <bean id="basicAuthenticationFilter"
          class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter"
          p:authenticationManager-ref="authenticationManager"
          p:authenticationEntryPoint-ref="basicAuthenticationEntryPoint" />

    <bean id="basicAuthenticationEntryPoint"
          class="webapp.PlainTextBasicAuthenticationEntryPoint"
          p:realmName="myWebapp"/>

    <bean id="formAuthenticationEntryPoint"
          class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
          p:loginFormUrl="/login.jsp"/>

    <bean id="daep" class="org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint">
        <constructor-arg>
            <map>
                <entry key="hasHeader('User-Agent','Mozilla') or hasHeader('User-Agent','Opera') or hasHeader('User-Agent','Explorer')" value-ref="formAuthenticationEntryPoint" />
            </map>
        </constructor-arg>
        <property name="defaultEntryPoint" ref="basicAuthenticationEntryPoint"/>
    </bean>

    <sec:http entry-point-ref="daep">
        <sec:intercept-url pattern="/login.jsp*" filters="none"/>
        <sec:intercept-url pattern="/json" access="ROLE_USER,ROLE_ADMIN"  />
        <sec:intercept-url pattern="/json/*" access="ROLE_USER,ROLE_ADMIN"  />
        <sec:logout
            logout-url="/logout"
            logout-success-url="/home.jsp"/>
        <sec:form-login
            login-page="/login.jsp"
            login-processing-url="/login"
            authentication-failure-url="/login.jsp?login_error=1" default-target-url="/home.jsp"/>
        <sec:custom-filter position="BASIC_AUTH_FILTER" ref="basicAuthenticationFilter" />
    </sec:http>

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

</beans>

PlainTextBasicAuthenticationEntryPoint by extending org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;

public class PlainTextBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\"");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status " + HttpServletResponse.SC_UNAUTHORIZED + " - " + authException.getMessage());
    }
}

这篇关于处理Spring Security中基本身份验证的未经授权的错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆