简体   繁体   中英

Spring-security-oauth OAuthProviderTokenServices custom implementation in OAuth 1.0

I'm using Spring-security-oauth to secure a RESTful application, and I'm triying to implement a custom OAuthProviderTokenServices class in order to store tokens in a database. All I got from the docs is:

When creating your OAuthProviderTokenServices implementation, you may want to consider extending the RandomValueProviderTokenServices which creates tokens via random value and handles everything except for the persistence of the tokens. There is also an in-memory implementation of the OAuthProviderTokenServices that may be suitable [...]

which is fine, so I created a new custom class:

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);
  }

}

which for now, as you can see, is identical to the InMemoryProviderTokenServices class.

My application uses the AccessConfirmationController from sparkl example, which is this:

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;
    }
}

Now the question is: how do I tell my application to use my tokenServices implementation rather than the default one (which right now I belive is InMemoryProviderTokenServices)?

I tried messing around with the controller, but the fews attempt all led me to java.lang.IllegalStateExceptions.

I also noticed that there is a line in the config XML:

<oauth:token-services id="tokenServices"/>

Which might be a critical piece of the puzzle, as the related help reads:

Element for declaring and configuring an in-memory implementation of the provider token service.

If I just remove it, I get:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accessConfirmationController' defined in ServletContext resource [/WEB-INF/mvc-dispatcher-servlet.xml]: Cannot resolve reference to bean 'tokenServices' while setting bean property 'tokenServices'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'tokenServices' is defined

Funny as answers come out of nowhere sometimes, expecially after it's been some time since you've started looking for them and you've just posted here. Oh well.

According to a code snippet randomly found here , it looks like all I needed to do was to comment out that line from the XML configuration file:

<!--   <oauth:token-services id="tokenServices"/> -->

and replace it with this one:

<beans:bean id="tokenServices" class="experiments.DatabaseProviderTokenServices" />

where the class is of course my implementation. By doing this, the DatabaseProviderTokenServices class is used in place of the default InMemoryProviderTokenServices class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM