服务器返回的HTTP响应code:400使用弹簧安全的AuthenticationProvider [英] Server returned HTTP response code: 400 using Spring-Security AuthenticationProvider

查看:281
本文介绍了服务器返回的HTTP响应code:400使用弹簧安全的AuthenticationProvider的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我建立一个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调用此方法:

  UsernamePasswordAut​​henticationToken令牌=
    新UsernamePasswordAut​​henticationToken(托马斯,托马斯);
UsernamePasswordAut​​henticationToken响应=
    调用(/身份验证,令牌,UsernamePasswordAut​​henticationToken.class);

下面是被调用模拟器方式:

  @RequestMapping(值=/身份验证,方法= RequestMethod.POST)
@ResponseBody
公共UsernamePasswordAut​​henticationToken身份验证(
    @RequestBody UsernamePasswordAut​​henticationToken userNameAndPassword){    字符串username =(字符串)userNameAndPassword.getPrincipal();
    字符串密码=(字符串)userNameAndPassword.getCredentials();
    如果(userName.equalsIgnoreCase(托马斯)){
        如果(userName.equals(密码)){
            UsernamePasswordAut​​henticationToken响应=
                新UsernamePasswordAut​​henticationToken(
                    用户名,
                        密码,
                        新的ArrayList<&GrantedAuthority的GT;());
                返回响应;
            }
        }
        返回新UsernamePasswordAut​​henticationToken(用户名,密码);
    }

这会导致错误的行是:

  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.UsernamePasswordAut​​henticationToken;
进口org.springframework.security.core.GrantedAuthority;公共类SerializedAuthenticationToken扩展UsernamePasswordAut​​henticationToken {
    私有静态最后的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();    UsernamePasswordAut​​henticationToken令牌=新UsernamePasswordAut​​henticationToken(托马斯,托马斯);
    字符串tokenStr = mapper.writeValueAsString(令牌);
    / *将无法正常工作
     UsernamePasswordAut​​henticationToken AUTH = mapper.readValue(tokenStr,UsernamePasswordAut​​henticationToken.class);
     * /
    即为MyToken AUTH = mapper.readValue(tokenStr,MyToken.class);
    字符串authStr = mapper.writeValueAsString(AUTH);    Assert.assertThat(tokenStr.equals(authStr),是(真));
}
私有静态类即为MyToken扩展UsernamePasswordAut​​henticationToken {
    私有对象主体;
    私有对象资格证书;    私有静态最后的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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆