使用INI使用Apache Shiro保护Apache CXF Web服务

时间:2012-07-06 20:04:38

标签: web-services cxf shiro

在这里需要帮助来保护简单的Apache CXF Web服务。使用Spring Security的尝试让我无处可去,所以我需要找到一个不同的策略。这是为了为我们的一些客户实现的遗留Java服务实现授权。

这个简单的Apache CXF Web服务是使用Maven的cxf-jaxws-javafirst原型创建的。 它生成了一个web.xml和beans.xml文件以及示例代码。除了保持默认状态的beans.xml之外,我还修改了这些实体,如下所示:

的web.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">


<web-app>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/beans.xml</param-value>
    </context-param>
     <context-param>
     <param-name>shiroConfigLocations</param-name>
        <param-value>WEB-INF/shiro.ini</param-value>
      </context-param>  

     <filter>
        <filter-name>ShiroFilter</filter-name>
        <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>       
    </filter>

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

    <listener>      
        <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
    </listener> 

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>      
    </listener>


    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <display-name>CXF Servlet</display-name>
        <servlet-class>
            org.apache.cxf.transport.servlet.CXFServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

和我的Shiro.ini文件如下所示:

# =======================
# Shiro INI configuration
# =======================

[main]
authc = org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

[users]
o = o, OPERATOR
a = a, ADMIN
s = s, SUPERVISOR

[roles]
SUPERVISOR = *
ADMIN = sayHiAdmin
OPERATOR = deleteAccounts

我的简单网络服务代码如下:

import javax.jws.WebService;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;

@WebService(endpointInterface = "org.myCo.com.CxfShiroSecuredService.HelloWorld")
public class HelloWorldImpl implements HelloWorld {

    public String sayHi(String text) {              

        if (isAuthorized("sayHi")) {
            return "Successfully said hi " + text;
        }               

        if (hasRole("OPERATOR")){
            return "User is OPERATOR";
        }
        if (hasRole("ADMIN")){
            return "User is OPERATOR";
        }
        throw new UnauthorizedException("Logged user does not have OPERATOR's permission");                             
    }    

    public String sayHiAdmin(String text) {         

        if (isAuthorized("sayHiAdmin")) {
            return "Successfully said hi Admin " + text;
        }               

        throw new UnauthorizedException("Logged user does not have ADMIN permission");
    }

    public String deleteAccounts(String text) {             

        if (isAuthorized("deleteAccounts")) {
            return "Successfully deleted accounts " + text;
        }               

        throw new UnauthorizedException("Logged user does not have SUPERVISOR permission");
    }

    private Boolean isAuthorized(String operation){
        Subject currentUser = SecurityUtils.getSubject();       
        return currentUser.isPermitted(operation);  //currentUser.isAuthenticated(); // && currentUser.isPermitted(operation);      
    }

    private Boolean hasRole(String role){
        Subject currentUser = SecurityUtils.getSubject();       
        return currentUser.hasRole(role);       
    }
}

我有一个C#测试客户端,在调用webservice之前传递SOAP头中的身份验证信息,如下所示:

 private void OnButtonClick(object sender, RoutedEventArgs e)
        {
            var client = new HelloWorldClient();
            var response = "";

            using (new OperationContextScope(client.InnerChannel))
            {
                var httpRequestProperty = new HttpRequestMessageProperty();
                httpRequestProperty.Headers[System.Net.HttpRequestHeader.Authorization] = "Basic " +
                Convert.ToBase64String(Encoding.ASCII.GetBytes(UserName.Text + ":" + Password.Text));
                OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;

                try
                {
                    response = client.sayHi("hi " + UserName.Text);
                }
                catch (TimeoutException tex)
                {
                    response = tex.Message;
                }
                catch (CommunicationException cex)
                {
                    response = cex.Message;
                }
            }

            TextBox.Text = response;

        }

我对其他需要基本身份验证的Web服务使用了相同的策略 在成功调用方法调用之前,此服务似乎没有识别我的凭据。对于调用的每个方法调用,无论用户名/密码组合如何,我都会抛出UnAuthorizedException。有人能给我一些启示吗?

提前致谢。

1 个答案:

答案 0 :(得分:2)

您的shiro.ini文件中需要[urls]部分。像这样:

[urls]
/** = authc

查看文档以获取更多详细信息here