服务器使用Spring Security AuthenticationProvider返回HTTP响应代码:400
我正在构建一个RESTful身份验证服务,但连接到它时遇到问题。在尝试检索响应时,我遇到了可怕的“服务器返回HTTP响应代码:400”。这似乎很奇怪。我想在发送请求时会出现这个错误 我将此服务用作Spring Security AuthenticationProvider的一部分。我目前正在使用模拟器而不是实际的服务进行测试。它不会连接到模拟器或服务 以下是调用方法:服务器使用Spring Security AuthenticationProvider返回HTTP响应代码:400,spring,http,authentication,spring-security,Spring,Http,Authentication,Spring Security,我正在构建一个RESTful身份验证服务,但连接到它时遇到问题。在尝试检索响应时,我遇到了可怕的“服务器返回HTTP响应代码:400”。这似乎很奇怪。我想在发送请求时会出现这个错误 我将此服务用作Spring Security AuthenticationProvider的一部分。我目前正在使用模拟器而不是实际的服务进行测试。它不会连接到模拟器或服务 以下是调用方法: public <T> T invoke(String service, Object request, Class&
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);
}
下面是调用的模拟器方法:
@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);
}
如果无法看到此代码的任何问题。一定是看得太久了。需要对这个问题有新的认识
顺便说一句,这个REST服务和模拟器已经成功地用于其他操作
其他信息:
错误发生在uc.getInputStream()调用中。HttpURLConnection.inputStream=null
此外,请求的标题如下所示:
如果这有帮助,以下是此请求的标题:
[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
以下是我的令牌代码:
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) {
}
}
我无法发现确切的问题,但我认为问题的一个原因是,您不必要地使用这种低级API来完成一些非常合理的抽象。看看Spring的RestTemplate,可以看到一种更优雅的方法,或者针对RESTful服务编写客户机代码。无论你做错了什么,RestTemplate都有可能做对。无法发现确切的问题,但我认为问题的一个原因是,你不必要地使用这样一个低级API来完成一些非常合理的抽象。看看Spring的RestTemplate,可以看到一种更优雅的方法,或者针对RESTful服务编写客户机代码。无论您做错了什么,RestTemplate都有可能纠正错误。您需要创建一个虚拟令牌来做到这一点。下面是我的测试来验证它:
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) {
}
}
}您需要创建一个虚拟令牌来执行此操作。下面是我的测试来验证它:
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) {
}
}
}我将查看REST模板。谢谢。当我使用RestTemplate时,我收到一条非常类似的错误消息:HttpClientErrorException:400错误请求。所以,这并没有解决任何问题。我将研究REST模板。谢谢。当我使用RestTemplate时,我收到一条非常类似的错误消息:HttpClientErrorException:400错误请求。因此,这并没有解决任何问题。实际错误发生在映射器参数中的uc.getInputStream()调用中。调试时,HttpURLConnection.inputStream为空。控制器的身份验证方法是否适用于其他应用程序?我认为您可能也必须在其中使用虚拟令牌,以便可以从JSON请求构造令牌对象:public usernamePasswordAuthenticationTokenAuthentication(@RequestBody MyToken userNameAndPassword){…}我更改了它,以便将对UsernamePasswordAuthenticationToken的所有引用替换为我的MyToken版本。不,authenticate()目前不适用于任何内容。我已在主要问题文本中添加了此请求的标题。您必须在令牌中添加布尔认证字段(及其setter和getter)。我认为没有必要扩展UsernamePasswordAuthenticationToken。您可以改为使用简单的POJO。实际错误发生在映射器参数中的uc.getInputStream()调用中。调试时,HttpURLConnection.inputStream为空。控制器的身份验证方法是否适用于其他应用程序?我认为您可能也必须在其中使用虚拟令牌,以便可以从JSON请求构造令牌对象:public usernamePasswordAuthenticationTokenAuthentication(@RequestBody MyToken userNameAndPassword){…}我更改了它,以便将对UsernamePasswordAuthenticationToken的所有引用替换为我的MyToken版本。不,authenticate()目前不适用于任何内容。我已在主要问题文本中添加了此请求的标题。您必须在令牌中添加布尔认证字段(及其setter和getter)。我认为没有必要扩展UsernamePasswordAuthenticationToken。您可以使用简单的POJO。
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"])
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) {
}
}