我正在实施一个客户端,使用OAuth2对WSO2进行身份验证,我在刷新访问令牌时遇到了严重问题,获得了401 UNAUTHORIZED。虽然我已经发现了Spring OAuth2代码的作用,但我不知道为什么它的行为在2.2.1.RELEASE中发生了变化,对我来说这似乎是完全错误的。实际上使用2.0.14.RELEASE可以工作。
在我向你展示之前,我已经做了什么以及我已经发现了什么之前,让我提出我的问题:
我应该如何使用客户端凭据而不是用户凭据来实现自动令牌刷新的OAuth2客户端?
所以这就是我到目前为止实施的内容。由于没有用户会话,客户端使用OAuth2RestTemplate
ResourceOwnerPasswordResourceDetails
标记isClientOnly
配置true
@Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails() {
@Override
public boolean isClientOnly() {
return true;
}
};
List<String> scopes = new ArrayList<>(2);
scopes.add("write");
scopes.add("read");
resource.setScope(scopes);
resource.setGrantType("password");
resource.setAccessTokenUri(TOKEN_URL);
resource.setClientId(MY_CLIENT_ID);
resource.setClientSecret(MY_CLIENT_SECRET);
resource.setUsername(MY_SERVICE_USER);
resource.setPassword(MY_SERVICE_USER_PW);
return resource;
}
@Bean
public OAuth2RestOperations restTemplate() {
AccessTokenRequest atr = new DefaultAccessTokenRequest();
OAuth2RestTemplate template = new OAuth2RestTemplateWithBasicAuth(resource(), new DefaultOAuth2ClientContext(atr));
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
interceptors.add(new LoggingRequestInterceptor());
template.setInterceptors(interceptors);
template.setRetryBadAccessTokens(true);
return template;
}
。可以成功建立客户端会话,并设置访问令牌和刷新令牌。
AccessTokenProviderChain#obtainAccessToken
到目前为止一切顺利。我已经证实这基本上有效。
但是一旦访问令牌过期,我经常遇到401错误,因为没有执行令牌刷新。相反,执行普通的身份验证请求,但使用客户端密钥和密码而不是用户/密码。简而言之,我已经通过spring-security-oauth2调试我的方式进入 if (resource.isClientOnly() || (auth != null && auth.isAuthenticated())) { // P1
existingToken = request.getExistingToken();
if (existingToken == null && clientTokenServices != null) {
existingToken = clientTokenServices.getAccessToken(resource, auth);
}
if (existingToken != null) {
if (existingToken.isExpired()) {
if (clientTokenServices != null) {
clientTokenServices.removeAccessToken(resource, auth);
}
OAuth2RefreshToken refreshToken = existingToken.getRefreshToken();
if (refreshToken != null && !resource.isClientOnly()) { // P2
accessToken = refreshAccessToken(resource, refreshToken, request);
}
}
else {
accessToken = existingToken;
}
}
}
并发现,是否执行了令牌刷新请求是在下面的代码中决定的。 See on Github
auth
正如您在P1处所见,如果存在授权用户会话(clientOnly
)或资源配置为isClientOnly() == true && auth == null
,则会输入阻止。由于我没有用户,但我处于链接服务方案中,我有!isClientOnly()
。但是在P2,实际进行刷新的最终决定是通过要求 try {
JSONArray jsonarray = new JSONArray(response);
for (int i = 0; i < jsonarray.length(); i++) {
JSONObject jsonobject = jsonarray.getJSONObject(i);
String name = jsonobject.getString("Sno");
String Tktid = jsonobject.getString("TKTID");
link = jsonobject.getString("Link");
List list = new List(jsonobject.getString("Sno"), jsonobject.getString("TKTID"),jsonobject.getString("Link"));
tktList.add(list);
Log.i("website content", name);
Log.i("website content", Tktid);
Log.i("website content", link);
}
//creating custom adapter object
ListViewAdapter adapter = new ListViewAdapter(tktList, getApplicationContext());
//adding the adapter to listview
listView.setAdapter(adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//displaying the error in toast if occurrs
Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
来规定的。因此,这仅在客户端方案中有效地禁止刷新请求。
这是2.2.1版本之前的版本,我发现,这似乎是对以下Issue的修复。对我来说,这似乎是完全错误的。
此外,对我来说,补丁似乎打破了客户端功能,以修复实际的服务器错误行为。正如您在问题讨论中看到的那样,我已经对此进行了评论。但是当这个问题被关闭并且spring-security-oauth2论坛指出应该在StackOverflow上进行讨论时,我在这里寻求帮助。
同样问题:如何将客户端应用程序配置为通过OAuth2RestTemplate使用OAuth2安全服务,以及一小时的访问令牌运行时和刷新令牌运行时(比方说两小时)。