我正在使用 Spring-security-oauth 来保护 RESTful 应用程序,并且我正在尝试实现自定义 OAuthProviderTokenServices 类以便将令牌存储在数据库中。我从文档中得到的只是:
创建 OAuthProviderTokenServices 实现时,您可能需要考虑扩展 RandomValueProviderTokenServices,它通过随机值创建令牌并处理除令牌持久性之外的所有内容。还有一个 OAuthProviderTokenServices 的内存实现可能适合 [...]
这很好,所以我创建了一个新的自定义类:
package experiments;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.security.oauth.provider.token.OAuthProviderTokenImpl;
import org.springframework.security.oauth.provider.token.RandomValueProviderTokenServices;
/**
* Implementation of TokenServices that stores tokens in a database.
*
* @author Seether
*/
public class DatabaseProviderTokenServices extends RandomValueProviderTokenServices {
protected final ConcurrentHashMap<String, OAuthProviderTokenImpl> tokenStore = new ConcurrentHashMap<String, OAuthProviderTokenImpl>();
protected OAuthProviderTokenImpl readToken(String token) {
return tokenStore.get(token);
}
protected void storeToken(String tokenValue, OAuthProviderTokenImpl token) {
tokenStore.put(tokenValue, token);
}
protected OAuthProviderTokenImpl removeToken(String tokenValue) {
return tokenStore.remove(tokenValue);
}
}
如您所见,它现在与 InMemoryProviderTokenServices 类相同。
我的应用程序使用 sparkl 示例中的 AccessConfirmationController,即:
package experiments;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.oauth.provider.ConsumerDetails;
import org.springframework.security.oauth.provider.ConsumerDetailsService;
import org.springframework.security.oauth.provider.token.OAuthProviderToken;
import org.springframework.security.oauth.provider.token.OAuthProviderTokenServices;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Controller for retrieving the model for and displaying the confirmation page for access to a protected resource.
*
* @author Ryan Heaton
*/
@Controller
public class AccessConfirmationController {
private OAuthProviderTokenServices tokenServices;
private ConsumerDetailsService consumerDetailsService;
@RequestMapping("/oauth/confirm_access")
public ModelAndView getAccessConfirmation(HttpServletRequest request, HttpServletResponse response)
throws Exception {
String token = request.getParameter("oauth_token");
if (token == null) {
throw new IllegalArgumentException("A request token to authorize must be provided.");
}
OAuthProviderToken providerToken = tokenServices.getToken(token);
ConsumerDetails consumer = consumerDetailsService
.loadConsumerByConsumerKey(providerToken.getConsumerKey());
String callback = request.getParameter("oauth_callback");
TreeMap<String, Object> model = new TreeMap<String, Object>();
model.put("oauth_token", token);
if (callback != null) {
model.put("oauth_callback", callback);
}
model.put("consumer", consumer);
return new ModelAndView("access_confirmation", model);
}
public void setTokenServices(OAuthProviderTokenServices tokenServices) {
this.tokenServices = tokenServices;
}
public void setConsumerDetailsService(ConsumerDetailsService consumerDetailsService) {
this.consumerDetailsService = consumerDetailsService;
}
}
现在的问题是:我如何告诉我的应用程序使用我的 tokenServices 实现而不是默认的实现(我现在相信是 InMemoryProviderTokenServices)?
我试着弄乱控制器,但几次尝试都把我带到了 java.lang.IllegalStateExceptions。
我还注意到配置 XML 中有一行:
<oauth:token-services id="tokenServices"/>
这可能是难题的关键部分,相关帮助如下:
用于声明和配置提供者令牌服务的内存实现的元素。
如果我只是删除它,我会得到:
org.springframework.beans.factory.BeanCreationException:创建 ServletContext 资源 [/WEB-INF/mvc-dispatcher-servlet.xml] 中定义的名称为“accessConfirmationController”的 bean 时出错:设置 bean 属性时无法解析对 bean 'tokenServices' 的引用令牌服务'; 嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'tokenServices' is defined