Comment utiliser OAuth2RestTemplate?

j'essaie de comprendre comment utiliser un objet OAuth2RestTemplate pour consommer mon service de repos sécurisé OAuth2 (qui fonctionne sous un autre projet et supposons aussi sur un autre serveur etc...)

F. E. mon service de repos est:

http://localhost:8082/app/helloworld

-> accéder à cette URL génère une erreur car je ne suis pas authentifié

Pour demander un jeton je voudrais aller à:

http://localhost:8082/app/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=**USERNAME**&password=**PASSWORD**

après avoir reçu le token, je peux me connecter à L'API REST en utilisant l'URL suivante (exemple jeton inséré)

http://localhost:8082/app/helloworld/?access_token=**4855f557-c6ee-43b7-8617-c24591965206**

maintenant, ma question Est de savoir comment implémenter une seconde application qui peut consommer cette API REST sécurisée OAuth2? Je n'ai vraiment trouvé aucun exemple de fonctionnement où vous fournissez le nom d'utilisateur et le mot de passe (par exemple venant d'un formulaire de connexion) et puis un jeton est généré qui peut être réutilisé pour obtenir des données à partir de L'API REST.

je suis actuellement essayé quelque chose avec les objets suivants:

BaseOAuth2ProtectedResourceDetails baseOAuth2ProtectedResourceDetails =  new BaseOAuth2ProtectedResourceDetails();
baseOAuth2ProtectedResourceDetails.setClientId("restapp");
baseOAuth2ProtectedResourceDetails.setClientSecret("restapp");
baseOAuth2ProtectedResourceDetails.setGrantType("password");
// how to set user name and password ???

DefaultAccessTokenRequest accessTokenRequest = new DefaultAccessTokenRequest();
OAuth2ClientContext oAuth2ClientContext = new DefaultOAuth2ClientContext(accessTokenRequest());

OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(baseOAuth2ProtectedResourceDetails,oAuth2ClientContext);

mais c'est juste ne fonctionne pas :(

toutes les idées sont grandement appréciées ou les liens vers des exemples de travail et des tutoriels sont grandement appréciés.

28
demandé sur Joachim Seminck 2015-01-09 18:50:49

3 réponses

Vous pouvez trouver des exemples pour écrire des clients de Oauth ici https://github.com/spring-projects/spring-security-oauth

dans votre cas, vous ne pouvez pas simplement utiliser les classes par défaut ou les classes de base pour tout, vous avez plusieurs classes qui implémentent OAuth2ProtectedResourceDetails. La configuration dépend de la façon dont vous avez configuré votre service Oauth, mais en supposant que de vos connexions curl Je recompose:

@EnableOAuth2Client
@Configuration
class MyConfig{




    @Value("${oauth.resource:http://localhost:8082}")
    private String baseUrl;
    @Value("${oauth.authorize:http://localhost:8082/oauth/authorize}")
    private String authorizeUrl;
    @Value("${oauth.token:http://localhost:8082/oauth/token}")
    private String tokenUrl


    @Bean
    protected OAuth2ProtectedResourceDetails resource() {

        ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();

        List scopes = new ArrayList<String>(2);
        scopes.add("write");
        scopes.add("read");
        resource.setAccessTokenUri(tokenUrl);
        resource.setClientId("restapp");
        resource.setClientSecret("restapp");
        resource.setGrantType("password");
        resource.setScope(scopes);

        resource.setUsername("**USERNAME**");
        resource.setPassword("**PASSWORD**");

        return resource;
    }

    @Bean
    public OAuth2RestOperations restTemplate() {
        AccessTokenRequest atr = new DefaultAccessTokenRequest();

        return new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(atr));
    }

}

@Service
@SuppressWarnings("unchecked")
class MyService {
    @Autowired
    private OAuth2RestOperations restTemplate;

    public MyService() {

        restTemplate.getAccessToken();
    }
}

n'oubliez pas @EnableOAuth2Client sur votre classe config, aussi je suggérerais d'essayer que les urls que vous utilisez fonctionnent avec curl en premier, aussi essayer de le tracer avec le débogueur parce que beaucoup d'exceptions sont juste consommées et jamais imprimées pour des raisons de sécurité, donc il est peu difficile de trouver où est le problème. Vous devriez utiliser l'enregistreur de débogage activé ensemble. Bonne chance

j'ai téléchargé l'échantillon springboot application sur github https://github.com/mariubog/oauth-client-sample pour dépeindre votre situation parce que je Je n'ai trouvé aucun échantillon pour votre scénario .

30
répondu mariubog 2016-08-10 13:41:58

j'ai autre approche si vous voulez jeton d'accès et de faire appel à d'autres ressources système avec jeton d'accès dans l'en-tête

la sécurité de ressort est livré avec la sécurité automatique: OAuth2 propriétés accès de l'application.le fichier yml pour chaque requête et chaque requête a un SESSIONID qu'il lit et tire les informations utilisateur via le Principal, donc vous devez vous assurer d'injecter le Principal dans OAuthUser et obtenir accessToken et faire appel au serveur de ressources

Ceci est votre application.yml, changer en fonction de votre auth server:

security:
  oauth2:
    client:
      clientId: 233668646673605
      clientSecret: 33b17e044ee6a4fa383f46ec6e28ea1d
      accessTokenUri: https://graph.facebook.com/oauth/access_token
      userAuthorizationUri: https://www.facebook.com/dialog/oauth
      tokenName: oauth_token
      authenticationScheme: query
      clientAuthenticationScheme: form
    resource:
      userInfoUri: https://graph.facebook.com/me

@Component
public class OAuthUser implements Serializable {

private static final long serialVersionUID = 1L;

private String authority;

@JsonIgnore
private String clientId;

@JsonIgnore
private String grantType;
private boolean isAuthenticated;
private Map<String, Object> userDetail = new LinkedHashMap<String, Object>();

@JsonIgnore
private String sessionId;

@JsonIgnore
private String tokenType;

@JsonIgnore
private String accessToken;

@JsonIgnore
private Principal principal;

public void setOAuthUser(Principal principal) {
    this.principal = principal;
    init();
}

public Principal getPrincipal() {
    return principal;
}

private void init() {
    if (principal != null) {
        OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) principal;
        if (oAuth2Authentication != null) {
            for (GrantedAuthority ga : oAuth2Authentication.getAuthorities()) {
                setAuthority(ga.getAuthority());
            }
            setClientId(oAuth2Authentication.getOAuth2Request().getClientId());
            setGrantType(oAuth2Authentication.getOAuth2Request().getGrantType());
            setAuthenticated(oAuth2Authentication.getUserAuthentication().isAuthenticated());

            OAuth2AuthenticationDetails oAuth2AuthenticationDetails = (OAuth2AuthenticationDetails) oAuth2Authentication
                    .getDetails();
            if (oAuth2AuthenticationDetails != null) {
                setSessionId(oAuth2AuthenticationDetails.getSessionId());
                setTokenType(oAuth2AuthenticationDetails.getTokenType());

            // This is what you will be looking for 
                setAccessToken(oAuth2AuthenticationDetails.getTokenValue());
            }

    // This detail is more related to Logged-in User
            UsernamePasswordAuthenticationToken userAuthenticationToken = (UsernamePasswordAuthenticationToken) oAuth2Authentication.getUserAuthentication();
            if (userAuthenticationToken != null) {
                LinkedHashMap<String, Object> detailMap = (LinkedHashMap<String, Object>) userAuthenticationToken.getDetails();
                if (detailMap != null) {
                    for (Map.Entry<String, Object> mapEntry : detailMap.entrySet()) {
                        //System.out.println("#### detail Key = " + mapEntry.getKey());
                        //System.out.println("#### detail Value = " + mapEntry.getValue());
                        getUserDetail().put(mapEntry.getKey(), mapEntry.getValue());
                    }

                }

            }

        }

    }
}


public String getAuthority() {
    return authority;
}

public void setAuthority(String authority) {
    this.authority = authority;
}

public String getClientId() {
    return clientId;
}

public void setClientId(String clientId) {
    this.clientId = clientId;
}

public String getGrantType() {
    return grantType;
}

public void setGrantType(String grantType) {
    this.grantType = grantType;
}

public boolean isAuthenticated() {
    return isAuthenticated;
}

public void setAuthenticated(boolean isAuthenticated) {
    this.isAuthenticated = isAuthenticated;
}

public Map<String, Object> getUserDetail() {
    return userDetail;
}

public void setUserDetail(Map<String, Object> userDetail) {
    this.userDetail = userDetail;
}

public String getSessionId() {
    return sessionId;
}

public void setSessionId(String sessionId) {
    this.sessionId = sessionId;
}

public String getTokenType() {
    return tokenType;
}

public void setTokenType(String tokenType) {
    this.tokenType = tokenType;
}

public String getAccessToken() {
    return accessToken;
}

public void setAccessToken(String accessToken) {
    this.accessToken = accessToken;
}

@Override
public String toString() {
    return "OAuthUser [clientId=" + clientId + ", grantType=" + grantType + ", isAuthenticated=" + isAuthenticated
            + ", userDetail=" + userDetail + ", sessionId=" + sessionId + ", tokenType="
            + tokenType + ", accessToken= " + accessToken + " ]";
}

@RestController
public class YourController {

@Autowired
OAuthUser oAuthUser;

// In case if you want to see Profile of user then you this 
@RequestMapping(value = "/profile", produces = MediaType.APPLICATION_JSON_VALUE)
public OAuthUser user(Principal principal) {
    oAuthUser.setOAuthUser(principal);

    // System.out.println("#### Inside user() - oAuthUser.toString() = " + oAuthUser.toString());

    return oAuthUser;
}


@RequestMapping(value = "/createOrder",
        method = RequestMethod.POST,
        headers = {"Content-type=application/json"},
        consumes = MediaType.APPLICATION_JSON_VALUE,
        produces = MediaType.APPLICATION_JSON_VALUE)
public FinalOrderDetail createOrder(@RequestBody CreateOrder createOrder) {

    return postCreateOrder_restTemplate(createOrder, oAuthUser).getBody();
}


private ResponseEntity<String> postCreateOrder_restTemplate(CreateOrder createOrder, OAuthUser oAuthUser) {

String url_POST = "your post url goes here";

    MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    headers.add("Authorization", String.format("%s %s", oAuthUser.getTokenType(), oAuthUser.getAccessToken()));
    headers.add("Content-Type", "application/json");

    RestTemplate restTemplate = new RestTemplate();
    //restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

    HttpEntity<String> request = new HttpEntity<String>(createOrder, headers);

    ResponseEntity<String> result = restTemplate.exchange(url_POST, HttpMethod.POST, request, String.class);
    System.out.println("#### post response = " + result);

    return result;
}


}
3
répondu Java_Fire_Within 2016-08-13 17:02:08

dans la réponse de @ mariubog (https://stackoverflow.com/a/27882337/1279002) j'utilisais des types de subvention de mot de passe aussi comme dans l'exemple mais j'avais besoin de définir le schéma d'authentification du client pour former. Les Scopes n'étaient pas pris en charge par le paramètre pour le mot de passe et il n'était pas nécessaire de définir le type de subvention puisque L'objet ResourceOwnerPasswordResourceDetails le définit lui-même dans le constructeur.

...

public ResourceOwnerPasswordResourceDetails() {
    setGrantType("password");
}

...

La clé de chose pour moi, le client_id et le client_secret n'étaient pas ajoutés à l'objet form pour être postés dans le corps si resource.setClientAuthenticationScheme(AuthenticationScheme.form); n'était pas fixé.

voir l'interrupteur dans: org.springframework.security.oauth2.client.token.auth.DefaultClientAuthenticationHandler.authenticateTokenRequest()

enfin, lors de la connexion à Salesforce endpoint, le token de mot de passe devait être ajouté au mot de passe.

@EnableOAuth2Client
@Configuration
class MyConfig {

@Value("${security.oauth2.client.access-token-uri}")
private String tokenUrl;

@Value("${security.oauth2.client.client-id}")
private String clientId;

@Value("${security.oauth2.client.client-secret}")
private String clientSecret;

@Value("${security.oauth2.client.password-token}")
private String passwordToken;

@Value("${security.user.name}")
private String username;

@Value("${security.user.password}")
private String password;


@Bean
protected OAuth2ProtectedResourceDetails resource() {

    ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();

    resource.setAccessTokenUri(tokenUrl);
    resource.setClientId(clientId);
    resource.setClientSecret(clientSecret);
    resource.setClientAuthenticationScheme(AuthenticationScheme.form);
    resource.setUsername(username);
    resource.setPassword(password + passwordToken);

    return resource;
}

@Bean
 public OAuth2RestOperations restTemplate() {
    return new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
    }
}


@Service
@SuppressWarnings("unchecked")
class MyService {
    @Autowired
    private OAuth2RestOperations restTemplate;

    public MyService() {
        restTemplate.getAccessToken();
    }
}
1
répondu theINtoy 2018-02-02 16:18:59