在这里迫切需要帮助保护一个简单的 Apache CXF Web 服务。Spring Security 的尝试让我无处可去,所以我需要找到不同的策略。这是为了在为我们的一些客户实现的遗留 Java 服务上实现授权。
这个简单的 Apache CXF Web 服务是使用 Maven 的 cxf-jaxws-javafirst 原型创建的。它生成了一个 web.xml 和 beans.xml 文件和示例代码。除了保持默认状态的 beans.xml 之外,我还对这些实体进行了如下修改:
网页.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# 测试客户端,它在调用 web 服务之前在 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。有人能给我一些启示吗?
提前致谢。