在 JBOSS EAP 6.3 中从 RESTFul 客户端(两者都在同一安全域中)调用 RESTFul Web 服务时出现 HTTP 错误 401
HTTP Error 401 while calling RESTFul Web service from a RESTFul client (both are on the same security domain) in JBOSS EAP 6.3
我有 2 个网络应用程序 - empService 和 empClient。我只是打印来自服务的 "Hello World" 消息。我将这两个应用程序放在同一个安全域中。当我直接调用我的服务应用程序时,它要求提供登录凭据以打开网页。但是当我从客户端调用它时,它会抛出 HTTP 错误 401(未经授权)。由于它们都使用相同的安全域,因此当我调用服务时,客户端也应该被授予访问权限。如果我需要在此处的代码中添加其他内容,有人可以告诉我吗?
empService
- src
- com.channel.employee.service
- Employee
- EmployeeService
- WebContent
- WEB-INF
- classes
- employee-roles.properties
- employee-users.properties
- jboss-web.xml
- web.xml
- hello.jsp
empClient
- src
- com.channel.employee.client
- EmployeeClient
- WebContent
- WEB-INF
- classes
- employee-roles.properties
- employee-users.properties
- jboss-web.xml
- web.xml
Employee.java
@Path("/")
public class Employee {
/*@Inject
static EmployeeService employeeService;*/
EmployeeService employeeService=new EmployeeService();
@GET
@Path("/xml")
@Produces({ "application/xml" })
@RolesAllowed({"employee"})
public String getHelloWorldXML() {
return "<xml><result>" + employeeService.createHelloMessage("Employee") + "</result></xml>";
}
}
EmployeeService.java
public class EmployeeService {
String createHelloMessage(String name) {
return "Hello " + name + "!";
}
}
employee-roles.properties
usaaemp1=employee
usaaemp2=employee
employee-users.properties
usaaemp1=usaaemp11
usaaemp2=usaaemp22
jboss-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<security-domain>java:/jaas/Employee</security-domain>
</jboss-web>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>empService</display-name>
<welcome-file-list>
<welcome-file>hello.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>resteasy.role.based.security</param-name>
<param-value>true</param-value>
</context-param>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/employee/*</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>EmployeeChannel</web-resource-name>
<url-pattern>/employee/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>employee</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<!-- <realm-name>Specify Realm Name Here</realm-name> -->
</login-config>
<security-role>
<role-name>employee</role-name>
</security-role>
</web-app>
hello.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<a href="employee/xml">Employee Channel</a>
</body>
</html>
EmployeeClient.java
public class EmployeeClient {
public static void main(String[] args){
try{
//Initiate a client request using the url as a parameter
ClientRequest request = new ClientRequest("http://localhost:8080/ent_securityprefs_empService/employee/xml");
request.accept("application/xml");
//To get the response based on the request
ClientResponse<String> response = request.get(String.class);
//Check the HTTP status of the request
//HTTP 200 indicates the request is OK
if(response.getStatus() != 200){
throw new RuntimeException("Failed request with HTTP status: "+response.getStatus());
}
//If we get a good response, now let's read it
BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(response.getEntity().getBytes())));
String output;
//Loop over the br in order to print out the contents
System.out.println("\n*** Response from Server ***\n");
while((output = br.readLine()) != null){
System.out.println(output);
}
} catch(ClientProtocolException cpe) {
System.err.println(cpe);
} catch(IOException ioe){
System.err.println(ioe);
} catch(Exception e){
System.err.println(e);
}
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>empClient</display-name>
<security-constraint>
<web-resource-collection>
<web-resource-name>EmployeeChannel</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>employee</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<!-- <realm-name>Specify Realm Name Here</realm-name> -->
</login-config>
<security-role>
<role-name>employee</role-name>
</security-role>
</web-app>
standalone-full.xml
<security-domain name="Employee" cache-type="default">
<authentication>
<login-module code="UsersRoles" flag="required">
<module-option name="usersProperties" value="employee-users.properties"/>
<module-option name="rolesProperties" value="employee-roles.properties"/>
</login-module>
</authentication>
</security-domain>
我认为您需要在客户请求期间发送 'login credentials'。
我建议始终查看服务器返回的错误代码,通常,他们会给出问题的解释。
10.4.2 401 Unauthorized
The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information. HTTP access authentication is explained in "HTTP Authentication: Basic and Digest Access Authentication"
以上引自:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
[编辑]
我没有像我应该的那样清楚地阅读你的 post,我没有注意到你的客户端是它自己的进程。
但我将保留原答案中的以下文字:
Even though your client and server are in the same application, an external http request is being made, meaning that the call will leave the JVM and then get routed back to the JVM by the underlying hardware and infrastructure.
Meaning, that your application will have to authenticate and authorize itself when calling itself via http(s).
[/edit]
我现在可以调用客户端而不会出现 401 错误。我不确定这对我有用,因为我尝试了很多不同的东西。
Employee.java
@Path("/")
public class Employee {
@Inject
static EmployeeService employeeService;
@GET
@Path("/xml")
@Produces({ "application/xml" })
@RolesAllowed({"employee"})
public String getHelloWorldXML() {
return "<xml><result>" + employeeService.createHelloMessage("Employee") + "</result></xml>";
}
}
已将 beans.xml 文件添加到 WEB-INF 文件夹。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<!-- An application that uses CDI must have a file named beans.xml.
The file can be completely empty (it has content only in certain
limited situations), but it must be present. -->
</beans>
我有 2 个网络应用程序 - empService 和 empClient。我只是打印来自服务的 "Hello World" 消息。我将这两个应用程序放在同一个安全域中。当我直接调用我的服务应用程序时,它要求提供登录凭据以打开网页。但是当我从客户端调用它时,它会抛出 HTTP 错误 401(未经授权)。由于它们都使用相同的安全域,因此当我调用服务时,客户端也应该被授予访问权限。如果我需要在此处的代码中添加其他内容,有人可以告诉我吗?
empService
- src
- com.channel.employee.service
- Employee
- EmployeeService
- WebContent
- WEB-INF
- classes
- employee-roles.properties
- employee-users.properties
- jboss-web.xml
- web.xml
- hello.jsp
empClient
- src
- com.channel.employee.client
- EmployeeClient
- WebContent
- WEB-INF
- classes
- employee-roles.properties
- employee-users.properties
- jboss-web.xml
- web.xml
Employee.java
@Path("/")
public class Employee {
/*@Inject
static EmployeeService employeeService;*/
EmployeeService employeeService=new EmployeeService();
@GET
@Path("/xml")
@Produces({ "application/xml" })
@RolesAllowed({"employee"})
public String getHelloWorldXML() {
return "<xml><result>" + employeeService.createHelloMessage("Employee") + "</result></xml>";
}
}
EmployeeService.java
public class EmployeeService {
String createHelloMessage(String name) {
return "Hello " + name + "!";
}
}
employee-roles.properties
usaaemp1=employee
usaaemp2=employee
employee-users.properties
usaaemp1=usaaemp11
usaaemp2=usaaemp22
jboss-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<security-domain>java:/jaas/Employee</security-domain>
</jboss-web>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>empService</display-name>
<welcome-file-list>
<welcome-file>hello.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>resteasy.role.based.security</param-name>
<param-value>true</param-value>
</context-param>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/employee/*</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>EmployeeChannel</web-resource-name>
<url-pattern>/employee/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>employee</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<!-- <realm-name>Specify Realm Name Here</realm-name> -->
</login-config>
<security-role>
<role-name>employee</role-name>
</security-role>
</web-app>
hello.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<a href="employee/xml">Employee Channel</a>
</body>
</html>
EmployeeClient.java
public class EmployeeClient {
public static void main(String[] args){
try{
//Initiate a client request using the url as a parameter
ClientRequest request = new ClientRequest("http://localhost:8080/ent_securityprefs_empService/employee/xml");
request.accept("application/xml");
//To get the response based on the request
ClientResponse<String> response = request.get(String.class);
//Check the HTTP status of the request
//HTTP 200 indicates the request is OK
if(response.getStatus() != 200){
throw new RuntimeException("Failed request with HTTP status: "+response.getStatus());
}
//If we get a good response, now let's read it
BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(response.getEntity().getBytes())));
String output;
//Loop over the br in order to print out the contents
System.out.println("\n*** Response from Server ***\n");
while((output = br.readLine()) != null){
System.out.println(output);
}
} catch(ClientProtocolException cpe) {
System.err.println(cpe);
} catch(IOException ioe){
System.err.println(ioe);
} catch(Exception e){
System.err.println(e);
}
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>empClient</display-name>
<security-constraint>
<web-resource-collection>
<web-resource-name>EmployeeChannel</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>employee</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<!-- <realm-name>Specify Realm Name Here</realm-name> -->
</login-config>
<security-role>
<role-name>employee</role-name>
</security-role>
</web-app>
standalone-full.xml
<security-domain name="Employee" cache-type="default">
<authentication>
<login-module code="UsersRoles" flag="required">
<module-option name="usersProperties" value="employee-users.properties"/>
<module-option name="rolesProperties" value="employee-roles.properties"/>
</login-module>
</authentication>
</security-domain>
我认为您需要在客户请求期间发送 'login credentials'。
我建议始终查看服务器返回的错误代码,通常,他们会给出问题的解释。
10.4.2 401 Unauthorized
The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information. HTTP access authentication is explained in "HTTP Authentication: Basic and Digest Access Authentication"
以上引自:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
[编辑]
我没有像我应该的那样清楚地阅读你的 post,我没有注意到你的客户端是它自己的进程。
但我将保留原答案中的以下文字:
Even though your client and server are in the same application, an external http request is being made, meaning that the call will leave the JVM and then get routed back to the JVM by the underlying hardware and infrastructure.
Meaning, that your application will have to authenticate and authorize itself when calling itself via http(s).
[/edit]
我现在可以调用客户端而不会出现 401 错误。我不确定这对我有用,因为我尝试了很多不同的东西。
Employee.java
@Path("/")
public class Employee {
@Inject
static EmployeeService employeeService;
@GET
@Path("/xml")
@Produces({ "application/xml" })
@RolesAllowed({"employee"})
public String getHelloWorldXML() {
return "<xml><result>" + employeeService.createHelloMessage("Employee") + "</result></xml>";
}
}
已将 beans.xml 文件添加到 WEB-INF 文件夹。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<!-- An application that uses CDI must have a file named beans.xml.
The file can be completely empty (it has content only in certain
limited situations), but it must be present. -->
</beans>