问题描述
我建立一个REST风格的认证服务,我在连接到它的麻烦。我得到了可怕的服务器返回的HTTP响应code:400的尝试检索响应时。这似乎很奇怪。我认为在发送请求时,我会得到这个错误。
我使用这个服务作为一个Spring安全的AuthenticationProvider的一部分。我目前使用模拟器,而不是测试实际的服务。它不会连接到任何模拟器或服务。
下面是调用方法:
公开< T> ŧ调用(字符串服务对象的要求,类< T>的responseType)抛出IOException
ObjectMapper映射器=新ObjectMapper();
网址URL =新的URL(HTTP://本地主机:8888 /模拟器/休息+服务);
HttpURLConnection的UC =(HttpURLConnection类)url.openConnection(); uc.setRequestMethod(POST);
uc.setRequestProperty(内容类型,应用/ JSON的;字符集= UTF-8);
uc.setDoOutput(真);
uc.setDoInput(真);
uc.connect(); OutputStream的OUT = uc.getOutputStream();
mapper.writeValue(满分,请求);
out.close(); 返回mapper.readValue(uc.getInputStream(),的responseType);
}
下面是code调用此方法:
UsernamePasswordAuthenticationToken令牌=
新UsernamePasswordAuthenticationToken(托马斯,托马斯);
UsernamePasswordAuthenticationToken响应=
调用(/身份验证,令牌,UsernamePasswordAuthenticationToken.class);
下面是被调用模拟器方式:
@RequestMapping(值=/身份验证,方法= RequestMethod.POST)
@ResponseBody
公共UsernamePasswordAuthenticationToken身份验证(
@RequestBody UsernamePasswordAuthenticationToken userNameAndPassword){ 字符串username =(字符串)userNameAndPassword.getPrincipal();
字符串密码=(字符串)userNameAndPassword.getCredentials();
如果(userName.equalsIgnoreCase(托马斯)){
如果(userName.equals(密码)){
UsernamePasswordAuthenticationToken响应=
新UsernamePasswordAuthenticationToken(
用户名,
密码,
新的ArrayList<&GrantedAuthority的GT;());
返回响应;
}
}
返回新UsernamePasswordAuthenticationToken(用户名,密码);
}
这会导致错误的行是:
mapper.readValue(uc.getInputStream(),responseTyp的);
如果不能看到这个code的任何问题。必须一直在寻找它太长。对这个问题需要新的眼睛。
顺便说一句,这个REST服务和模拟器已成功地与其他操作使用。
其他信息:
在uc.getInputStream()调用时发生错误。该HttpURLConnection.inputStream = NULL。
另外,对于请求的标头,如下所示:
如果这会有所帮助,这里有此请求的报头:
[WARN] 400 - POST /模拟/ REST /认证(127.0.0.1)1417字节
请求头
内容类型:应用程序/ JSON的;字符集= UTF-8
的X租户:1
授权:0000013770b132a1dfcbfe0a694542b244534e0e406cfa857660c904daa89af91d0ac769
缓存控制:无缓存
编译:无缓存
用户代理:的Java / 1.6.0_26
主机:本地主机:8888
接受:text / html的,图像/ GIF,图像/ JPEG,*; Q = 2,* / *; Q = 0.2
连接:保持活动
内容长度:112
响应报头
设置Cookie:JSESSIONID = 1r02p7yvm8mzs;路径= /
X-UA-兼容:IE = 9
内容类型:text / html的;字符集= ISO-8859-1
内容长度:1417
下面是我的令牌code:
进口的java.util.List;进口org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
进口org.springframework.security.core.GrantedAuthority;公共类SerializedAuthenticationToken扩展UsernamePasswordAuthenticationToken {
私有静态最后的serialVersionUID长= 2783395505630241326L; 私有对象主体;
私有对象资格证书; / **
*无参数的构造函数,以满足序列化。
* /
公共SerializedAuthenticationToken(){
超(NULL,NULL);
} / **
*构造函数。
* /
公共SerializedAuthenticationToken(对象主体,对象凭证){
超(NULL,NULL);
setPrincipal(本金);
setCredentials方法(凭证);
} / **
*构造函数列表< GrantedAuthorities取代。
* /
公共SerializedAuthenticationToken(对象主体,对象凭证,列表与LT;&GrantedAuthority的GT;当局){
超(NULL,NULL,当局);
setPrincipal(本金);
setCredentials方法(凭证);
} 公共对象getPrincipal(){
返回本金;
} 公共无效setPrincipal(对象主体){
this.principal =本金;
} 公共对象getCredentials(显示){
返回证书;
} 公共无效setCredentials方法(对象凭证){
this.credentials =凭证;
} 公共无效setname可以(对象名称){ }
}
我现在也正在获得新的堆栈跟踪:
组织codehaus.jackson.map.JsonMappingException:无法设置此令牌信任 - 使用构造函数这需要一个GrantedAuthority列表,而不是(通过参考链。com.mckesson.shared .util.SerializedAuthenticationToken [认证])
您需要创建一个虚拟令牌来做到这一点。下面是我的测试,以验证:
公共类JacksonTest {@测试
公共无效测试()抛出异常{ ObjectMapper映射器=新ObjectMapper(); UsernamePasswordAuthenticationToken令牌=新UsernamePasswordAuthenticationToken(托马斯,托马斯);
字符串tokenStr = mapper.writeValueAsString(令牌);
/ *将无法正常工作
UsernamePasswordAuthenticationToken AUTH = mapper.readValue(tokenStr,UsernamePasswordAuthenticationToken.class);
* /
即为MyToken AUTH = mapper.readValue(tokenStr,MyToken.class);
字符串authStr = mapper.writeValueAsString(AUTH); Assert.assertThat(tokenStr.equals(authStr),是(真));
}
私有静态类即为MyToken扩展UsernamePasswordAuthenticationToken {
私有对象主体;
私有对象资格证书; 私有静态最后的serialVersionUID长= -5045038656629236029L; 公共即为MyToken(){ 超(NULL,NULL);
} 公共即为MyToken(对象主体,对象凭证){ 超(NULL,NULL);
this.principal =本金;
this.credentials =凭证;
} / **
返回:校长
* /
公共对象getPrincipal(){
返回本金;
} / **
* @参数校长的主要设置
* /
公共无效setPrincipal(对象主体){
this.principal =本金;
} / **
返回:凭据
* /
公共对象getCredentials(显示){
返回证书;
} / **
* @参数凭据设置凭据
* /
公共无效setCredentials方法(对象凭证){
this.credentials =凭证;
}
公共无效setname可以(对象名称){ }}
}
I'm building a RESTful authentication service and I'm having trouble connecting to it. I get the dreaded "Server returned HTTP response code: 400" when trying to retrieve the response. This seems very odd. I would think I'd get this error when sending the request.
I'm using this service as part of a Spring-Security AuthenticationProvider. I'm currently using a simulator instead of the actual service for testing. It won't connect to either the simulator or the service.
Here is the calling method:
public <T> T invoke(String service, Object request, Class<T> responseType) throws IOException {
ObjectMapper mapper = new ObjectMapper();
URL url = new URL("http://localhost:8888/simulator/rest" + service);
HttpURLConnection uc = (HttpURLConnection) url.openConnection();
uc.setRequestMethod("POST");
uc.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
uc.setDoOutput(true);
uc.setDoInput(true);
uc.connect();
OutputStream out = uc.getOutputStream();
mapper.writeValue(out, request);
out.close();
return mapper.readValue(uc.getInputStream(), responseType);
}
Here is the code that calls this method:
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken("thomas", "thomas");
UsernamePasswordAuthenticationToken response =
invoke("/authenticate", token, UsernamePasswordAuthenticationToken.class);
Here is the simulator method that gets called:
@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
@ResponseBody
public UsernamePasswordAuthenticationToken authenticate(
@RequestBody UsernamePasswordAuthenticationToken userNameAndPassword) {
String userName = (String) userNameAndPassword.getPrincipal();
String password = (String) userNameAndPassword.getCredentials();
if (userName.equalsIgnoreCase("thomas")) {
if (userName.equals(password)) {
UsernamePasswordAuthenticationToken response =
new UsernamePasswordAuthenticationToken(
userName,
password,
new ArrayList<GrantedAuthority>());
return response;
}
}
return new UsernamePasswordAuthenticationToken(userName, password);
}
The line that causes the error is the :
mapper.readValue(uc.getInputStream(), responseType);
If can't see any issues with this code. Must have been looking at it too long. Need new eyes on the problem.
BTW, this REST service and simulator has been used successfully with other operations.
Additional Information:
The error occurs in the uc.getInputStream() call. The HttpURLConnection.inputStream = null.
Also, the headers for the request are as follows:
If this helps, here are the headers for this request:
[WARN] 400 - POST /simulator/rest/authenticate (127.0.0.1) 1417 bytes
Request headers
Content-Type: application/json;charset=UTF-8
X-Tenant: 1
Authorization: 0000013770b132a1dfcbfe0a694542b244534e0e406cfa857660c904daa89af91d0ac769
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.6.0_26
Host: localhost:8888
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Length: 112
Response headers
Set-Cookie: JSESSIONID=1r02p7yvm8mzs;Path=/
X-UA-Compatible: IE=9
Content-Type: text/html; charset=iso-8859-1
Content-Length: 1417
Here is the my Token code:
import java.util.List;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
public class SerializedAuthenticationToken extends UsernamePasswordAuthenticationToken {
private static final long serialVersionUID = 2783395505630241326L;
private Object principal;
private Object credentials;
/**
* no-arg constructor to satisfy Serializable.
*/
public SerializedAuthenticationToken() {
super(null, null);
}
/**
* constructor.
*/
public SerializedAuthenticationToken(Object principal, Object credentials) {
super(null, null);
setPrincipal(principal);
setCredentials(credentials);
}
/**
* constructor with List<GrantedAuthorities>.
*/
public SerializedAuthenticationToken(Object principal, Object credentials, List<GrantedAuthority> authorities) {
super(null, null, authorities);
setPrincipal(principal);
setCredentials(credentials);
}
public Object getPrincipal() {
return principal;
}
public void setPrincipal(Object principal) {
this.principal = principal;
}
public Object getCredentials() {
return credentials;
}
public void setCredentials(Object credentials) {
this.credentials = credentials;
}
public void setName(Object name) {
}
}
I also now am getting a new stack trace:
org.codehaus.jackson.map.JsonMappingException: Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead (through reference chain: com.mckesson.shared.util.SerializedAuthenticationToken["authenticated"])
You need to create a Dummy token to do that. Here is my test to verify it:
public class JacksonTest {
@Test
public void test() throws Exception {
ObjectMapper mapper = new ObjectMapper();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("thomas", "thomas");
String tokenStr = mapper.writeValueAsString(token);
/* WON'T WORK
UsernamePasswordAuthenticationToken auth = mapper.readValue(tokenStr, UsernamePasswordAuthenticationToken.class);
*/
MyToken auth = mapper.readValue(tokenStr, MyToken.class);
String authStr = mapper.writeValueAsString(auth);
Assert.assertThat(tokenStr.equals(authStr), is(true));
}
private static class MyToken extends UsernamePasswordAuthenticationToken {
private Object principal;
private Object credentials;
private static final long serialVersionUID = -5045038656629236029L;
public MyToken() {
super(null, null);
}
public MyToken(Object principal, Object credentials) {
super(null, null);
this.principal = principal;
this.credentials = credentials;
}
/**
* @return the principal
*/
public Object getPrincipal() {
return principal;
}
/**
* @param principal the principal to set
*/
public void setPrincipal(Object principal) {
this.principal = principal;
}
/**
* @return the credentials
*/
public Object getCredentials() {
return credentials;
}
/**
* @param credentials the credentials to set
*/
public void setCredentials(Object credentials) {
this.credentials = credentials;
}
public void setName(Object name) {
}
}
}
这篇关于服务器返回的HTTP响应code:400使用弹簧安全的AuthenticationProvider的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!