如何解决使用RestTemplate的Spring Security身份验证
我当时的情况也一样。这是我的解决方案。
服务器-Spring Security配置
<sec:http>
<sec:intercept-url pattern="/**" access="ROLE_USER" method="POST"/>
<sec:intercept-url pattern="/**" filters="none" method="GET"/>
<sec:http-basic />
</sec:http>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider>
<sec:user-service>
<sec:user name="${rest.username}" password="${rest.password}" authorities="ROLE_USER"/>
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
客户端RestTemplate配置
<bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
<constructor-arg ref="httpClientParams"/>
<property name="state" ref="httpState"/>
</bean>
<bean id="httpState" class="CustomHttpState">
<property name="credentials" ref="credentials"/>
</bean>
<bean id="credentials" class="org.apache.commons.httpclient.UsernamePasswordCredentials">
<constructor-arg value="${rest.username}"/>
<constructor-arg value="${rest.password}"/>
</bean>
<bean id="httpClientFactory" class="org.springframework.http.client.CommonsClientHttpRequestFactory">
<constructor-arg ref="httpClient"/>
</bean>
<bean class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="httpClientFactory"/>
</bean>
自定义HttpState实现
/**
* Custom implementation of {@link HttpState} with credentials property.
*
* @author banterCZ
*/
public class CustomHttpState extends HttpState {
/**
* Set credentials property.
*
* @param credentials
* @see #setCredentials(org.apache.commons.httpclient.auth.AuthScope, org.apache.commons.httpclient.Credentials)
*/
public void setCredentials(final Credentials credentials) {
super.setCredentials(AuthScope.ANY, credentials);
}
}
Maven依赖
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
这是一个与Spring 3.1和Apache HttpComponents 4.1配合使用的很好的解决方案,我是根据该站点上的各种答案创建的,并阅读了Spring RestTempalte源代码。我希望能够节省其他人的时间,我认为spring应该只内置一些像这样的代码,但事实并非如此。
RestClient client = new RestClient();
client.setApplicationPath("someApp");
String url = client.login("theuser", "123456");
UserPortfolio portfolio = client.template().getForObject(client.apiUrl("portfolio"),
UserPortfolio.class);
下面是Factory类,该类将HttpComponents上下文设置为与使用RestTemplate的每个请求相同。
public class StatefullHttpComponentsClientHttpRequestFactory extends
HttpComponentsClientHttpRequestFactory
{
private final HttpContext httpContext;
public StatefullHttpComponentsClientHttpRequestFactory(HttpClient httpClient, HttpContext httpContext)
{
super(httpClient);
this.httpContext = httpContext;
}
@Override
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri)
{
return this.httpContext;
}
}
以下是Statefull Rest模板,你可以使用它来记住cookie,一旦登录,它就会记住JSESSIONID并在后续请求中发送。
public class StatefullRestTemplate extends RestTemplate
{
private final HttpClient httpClient;
private final CookieStore cookieStore;
private final HttpContext httpContext;
private final StatefullHttpComponentsClientHttpRequestFactory statefullHttpComponentsClientHttpRequestFactory;
public StatefullRestTemplate()
{
super();
httpClient = new DefaultHttpClient();
cookieStore = new BasicCookieStore();
httpContext = new BasicHttpContext();
httpContext.setAttribute(ClientContext.COOKIE_STORE, getCookieStore());
statefullHttpComponentsClientHttpRequestFactory = new StatefullHttpComponentsClientHttpRequestFactory(httpClient, httpContext);
super.setRequestFactory(statefullHttpComponentsClientHttpRequestFactory);
}
public HttpClient getHttpClient()
{
return httpClient;
}
public CookieStore getCookieStore()
{
return cookieStore;
}
public HttpContext getHttpContext()
{
return httpContext;
}
public StatefullHttpComponentsClientHttpRequestFactory getStatefulHttpClientRequestFactory()
{
return statefullHttpComponentsClientHttpRequestFactory;
}
}
这是一个代表其他客户端的类,因此你可以调用受spring安全保护的应用程序。
public class RestClient
{
private String host = "localhost";
private String port = "8080";
private String applicationPath;
private String apiPath = "api";
private String loginPath = "j_spring_security_check";
private String logoutPath = "logout";
private final String usernameInputFieldName = "j_username";
private final String passwordInputFieldName = "j_password";
private final StatefullRestTemplate template = new StatefullRestTemplate();
/**
* This method logs into a service by doing an standard http using the configuration in this class.
*
* @param username
* the username to log into the application with
* @param password
* the password to log into the application with
*
* @return the url that the login redirects to
*/
public String login(String username, String password)
{
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.add(usernameInputFieldName, username);
form.add(passwordInputFieldName, password);
URI location = this.template.postForLocation(loginUrl(), form);
return location.toString();
}
/**
* logout by doing an http get on the logout url
*
* @return result of the get as ResponseEntity
*/
public ResponseEntity<String> logout()
{
return this.template.getForEntity(logoutUrl(), String.class);
}
public String applicationUrl(String relativePath)
{
return applicationUrl() + "/" + checkNotNull(relativePath);
}
public String apiUrl(String relativePath)
{
return applicationUrl(apiPath + "/" + checkNotNull(relativePath));
}
public StatefullRestTemplate template()
{
return template;
}
public String serverUrl()
{
return "http://" + host + ":" + port;
}
public String applicationUrl()
{
return serverUrl() + "/" + nullToEmpty(applicationPath);
}
public String loginUrl()
{
return applicationUrl(loginPath);
}
public String logoutUrl()
{
return applicationUrl(logoutPath);
}
public String apiUrl()
{
return applicationUrl(apiPath);
}
public void setlogoutPath(String logoutPath)
{
this.logoutPath = logoutPath;
}
public String getHost()
{
return host;
}
public void setHost(String host)
{
this.host = host;
}
public String getPort()
{
return port;
}
public void setPort(String port)
{
this.port = port;
}
public String getApplicationPath()
{
return applicationPath;
}
public void setApplicationPath(String contextpath)
{
this.applicationPath = contextpath;
}
public String getApiPath()
{
return apiPath;
}
public void setApiPath(String apiPath)
{
this.apiPath = apiPath;
}
public String getLoginPath()
{
return loginPath;
}
public void setLoginPath(String loginPath)
{
this.loginPath = loginPath;
}
public String getlogoutPath()
{
return logoutPath;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("RestClient [\n serverUrl()=");
builder.append(serverUrl());
builder.append(", \n applicationUrl()=");
builder.append(applicationUrl());
builder.append(", \n loginUrl()=");
builder.append(loginUrl());
builder.append(", \n logoutUrl()=");
builder.append(logoutUrl());
builder.append(", \n apiUrl()=");
builder.append(apiUrl());
builder.append("\n]");
return builder.toString();
}
}
解决方法
我有2个Spring Web应用程序,它们提供2套独立的服务。Web App 1具有使用基于用户的身份验证实现的Spring Security。
现在,Web App 2需要访问Web App 1的服务。通常,我们将使用RestTemplate类向其他Web服务发出请求。
我们如何将Web App 2的请求中的身份验证凭据传递给Web App 1
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。