6
5

More than 5 years have passed since last update.

Apache Oltuを使ったOAuth認証のサンプルコード

Posted at

概要

Apache Oltuを使ったOAuth認証のサンプルコードです。
このライブラリの検証目的に作成しました。

環境

  • Windows7 (64bit)
  • Java 1.8.0_65
  • Spring-Boot 1.3.0
  • Apache Oltu 1.0.1

参考

サンプルコード

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example.sbsns.oltu</groupId>
  <artifactId>sbsns-oltu-example</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>sbsns-oltu-example</name>
  <url>http://maven.apache.org</url>

  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.0.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <dependency>
      <groupId>org.apache.oltu.oauth2</groupId>
      <artifactId>org.apache.oltu.oauth2.client</artifactId>
      <version>1.0.1</version>
    </dependency>

    <dependency>
      <groupId>org.codehaus.jackson</groupId>
      <artifactId>jackson-core-asl</artifactId>
      <version>1.9.13</version>
    </dependency>

    <dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.4</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

application.yml

# EMBEDDED SERVER CONFIGURATION (ServerProperties)
server:
  port: 9000

spring:
# PROFILES
  profiles:
    active: dev
# THYMELEAF (ThymeleafAutoConfiguration)
  thymeleaf:
    enabled: true
    cache: false

facebook:
  app-id: <facebook-app-id>
  app-secret: <faceboo-app-secret>
google:
  app-id: <google-app-id>
  app-secret: <google-app-secret>

Googleのサンプル

Config

package com.example.sbsns.oltu;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GoogleConfig {

  @Value("${google.app-id}")
  private String appId;
  @Value("${google.app-secret}")
  private String appSecret;

  public String getAppId() {
    return appId;
  }
  public String getAppSecret() {
    return appSecret;
  }
}

Form

package com.example.sbsns.oltu.web;

public class GoogleOAuthCallbackForm {

  private String code;
  private String state;
  private String error;

  public String getCode() {
    return code;
  }
  public void setCode(String code) {
    this.code = code;
  }
  public String getState() {
    return state;
  }
  public void setState(String state) {
    this.state = state;
  }
  public String getError() {
    return error;
  }
  public void setError(String error) {
    this.error = error;
  }

  @Override
  public String toString() {
    return "GoogleAuthCallbackForm [code=" + code + ", state=" + state
        + ", error=" + error + "]";
  }

}

Controller

package com.example.sbsns.oltu.web;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.URLConnectionClient;
import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse;
import org.apache.oltu.oauth2.client.response.OAuthAuthzResponse;
import org.apache.oltu.oauth2.client.response.OAuthResourceResponse;
import org.apache.oltu.oauth2.common.OAuthProviderType;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.example.sbsns.oltu.GoogleConfig;
import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
@RequestMapping(value = "/google")
public class GoogleOAuthController {
  private static Logger logger = LoggerFactory.getLogger(GoogleOAuthController.class);

  @Autowired
  private GoogleConfig config;

  private static final String REDIRECT_URI = "http://localhost:9000/google/callback";

  private static final String API_USER_INFO_ENDPOINT = "https://www.googleapis.com/oauth2/v1/userinfo";
  private static final String API_REVOKE_ENDPOINT = "https://accounts.google.com/o/oauth2/revoke";
  //private static final String API_GOOGLE_PLUS_ENDPOINT = "https://www.googleapis.com/plus/v1/people/me";

  @RequestMapping(value = "/signin", method = RequestMethod.GET)
  public void signin(
      HttpServletRequest request,
      HttpServletResponse response,
      Model model) throws IOException, OAuthSystemException {
    logger.info("signin");

    String state = "abc123xyz456";

    OAuthClientRequest clientRequest = OAuthClientRequest
        .authorizationProvider(OAuthProviderType.GOOGLE)
        .setClientId(config.getAppId())
        .setRedirectURI(REDIRECT_URI)
        .setResponseType("code")
        .setState(state)
        .setScope("https://www.googleapis.com/auth/userinfo.email")
        .buildQueryMessage();

    String redirectURL = clientRequest.getLocationUri();
    logger.info("locationURL:{}", redirectURL);

    response.sendRedirect(clientRequest.getLocationUri());
  }

  @RequestMapping(value = "/callback", method = RequestMethod.GET)
  public String callback(
      GoogleOAuthCallbackForm form,
      HttpServletRequest request,
      HttpServletResponse response,
      Model model) throws OAuthProblemException, OAuthSystemException {
    logger.info("callback");
    logger.info("form:{}", form);

    String code;
    String state;
    try {
      OAuthAuthzResponse oar = OAuthAuthzResponse.oauthCodeAuthzResponse(request);
      code = oar.getCode();
      state = oar.getState();
      logger.info("code:{}", code);
      logger.info("state:{}", state);
    } catch (OAuthProblemException e) {
      logger.error("OAuth response error", e);
      return "redirect:/";
    }

    OAuthClientRequest oauthRequest = OAuthClientRequest
        .tokenProvider(OAuthProviderType.GOOGLE)
        .setClientId(config.getAppId())
        .setClientSecret(config.getAppSecret())
        .setRedirectURI(REDIRECT_URI)
        .setGrantType(GrantType.AUTHORIZATION_CODE)
        .setCode(code)
        .buildBodyMessage();

    OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient()); 
    final OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(oauthRequest, "POST");

    String accessToken = oAuthResponse.getAccessToken();
    String scope = oAuthResponse.getScope();
    long expiresIn = oAuthResponse.getExpiresIn();

    logger.info("oAuthResponse:{}", oAuthResponse.toString());
    logger.info("accessToken:{}", accessToken);
    logger.info("scope:{}", scope);
    logger.info("expiresIn:{}", expiresIn);

    request.getSession().setAttribute("accessToken", accessToken);

    return "google/callback";
  }

  @RequestMapping(value = "/user", method = RequestMethod.GET)
  public String user(
      HttpServletRequest request,
      HttpServletResponse response,
      Model model) throws OAuthSystemException, OAuthProblemException {
    logger.info("user");

    String accessToken = (String) request.getSession().getAttribute("accessToken");

    OAuthClientRequest bearerClientRequest =
        new OAuthBearerClientRequest(API_USER_INFO_ENDPOINT)
              .setAccessToken(accessToken)
              .buildQueryMessage();

    logger.info("locationURL:{}", bearerClientRequest.getLocationUri());

    OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
    OAuthResourceResponse resourceResponse = oAuthClient.resource(bearerClientRequest, "GET", OAuthResourceResponse.class);

    String userinfoJSON = resourceResponse.getBody();
    logger.info("json:{}", userinfoJSON);

    try {
      GoogleUserProfile userProfile = new ObjectMapper().readValue(userinfoJSON, GoogleUserProfile.class);
      model.addAttribute("userProfile", userProfile);
      logger.info("{}", userProfile.toString());
    } catch (IOException e) {
      logger.error("Json parse error", e);
      return "redirect:/";
    }

    return "google/user";
  }

  @RequestMapping(value = "/signout", method = RequestMethod.GET)
  public String signout(
      HttpServletRequest request,
      HttpServletResponse response,
      Model model) throws IOException, OAuthSystemException, OAuthProblemException {
    logger.info("signout");

    String accessToken = (String) request.getSession().getAttribute("accessToken");

    OAuthClientRequest bearerClientRequest =
        new OAuthBearerClientRequest(API_REVOKE_ENDPOINT + "?token=" + accessToken)
             .buildQueryMessage();

    OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
    OAuthResourceResponse resourceResponse = oAuthClient.resource(bearerClientRequest, "GET", OAuthResourceResponse.class);
    String json = resourceResponse.getBody();
    logger.info("json:{}", json);

    return "index";
  }

}

Response Object

package com.example.sbsns.oltu.web;

import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown=true)
public class GoogleUserProfile implements Serializable {

  private static final long serialVersionUID = 3543234712791418623L;

  @JsonProperty("id")
  private String id;
  @JsonProperty("name")
  private String name;
  @JsonProperty("gender")
  private String gender;
  @JsonProperty("given_name")
  private String givenName;
  @JsonProperty("family_name")
  private String familyName;
  @JsonProperty("verified_email")
  private boolean verifiedEmail;
  @JsonProperty("email")
  private String email;
  @JsonProperty("picture")
  private String picture;
  @JsonProperty("link")
  private String link;

  public String getId() {
    return id;
  }
  public void setId(String id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getGender() {
    return gender;
  }
  public void setGender(String gender) {
    this.gender = gender;
  }
  public String getGivenName() {
    return givenName;
  }
  public void setGivenName(String givenName) {
    this.givenName = givenName;
  }
  public String getFamilyName() {
    return familyName;
  }
  public void setFamilyName(String familyName) {
    this.familyName = familyName;
  }
  public boolean isVerifiedEmail() {
    return verifiedEmail;
  }
  public void setVerifiedEmail(boolean verifiedEmail) {
    this.verifiedEmail = verifiedEmail;
  }
  public String getEmail() {
    return email;
  }
  public void setEmail(String email) {
    this.email = email;
  }
  public String getPicture() {
    return picture;
  }
  public void setPicture(String picture) {
    this.picture = picture;
  }
  public String getLink() {
    return link;
  }
  public void setLink(String link) {
    this.link = link;
  }

  @Override
  public String toString() {
    return "GoogleUserProfile [id=" + id + ", name=" + name + ", gender="
        + gender + ", givenName=" + givenName + ", familyName=" + familyName
        + ", verifiedEmail=" + verifiedEmail + ", email=" + email
        + ", picture=" + picture + ", link=" + link + "]";
  }

}

Facebookのサンプル

Config

package com.example.sbsns.oltu;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FacebookConfig {

  @Value("${facebook.app-id}")
  private String appID;
  @Value("${facebook.app-secret}")
  private String appSecret;

  public String getAppID() {
    return appID;
  }
  public String getAppSecret() {
    return appSecret;
  }
}

Form

package com.example.sbsns.oltu.web;

public class FacebookOAuthCallbackForm {

  private String code;
  private String state;
  private String error;
  private String error_code;
  private String error_description;
  private String error_reason;

  public String getCode() {
    return code;
  }
  public void setCode(String code) {
    this.code = code;
  }
  public String getState() {
    return state;
  }
  public void setState(String state) {
    this.state = state;
  }
  public String getError() {
    return error;
  }
  public void setError(String error) {
    this.error = error;
  }
  public String getError_code() {
    return error_code;
  }
  public void setError_code(String error_code) {
    this.error_code = error_code;
  }
  public String getError_description() {
    return error_description;
  }
  public void setError_description(String error_description) {
    this.error_description = error_description;
  }
  public String getError_reason() {
    return error_reason;
  }
  public void setError_reason(String error_reason) {
    this.error_reason = error_reason;
  }

  @Override
  public String toString() {
    return "FacebookAuthCallbackForm [code=" + code + ", state=" + state
        + ", error=" + error + ", error_code=" + error_code
        + ", error_description=" + error_description + ", error_reason="
        + error_reason + "]";
  }

}

Controller

package com.example.sbsns.oltu.web;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.URLConnectionClient;
import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.GitHubTokenResponse;
import org.apache.oltu.oauth2.client.response.OAuthAuthzResponse;
import org.apache.oltu.oauth2.client.response.OAuthResourceResponse;
import org.apache.oltu.oauth2.common.OAuthProviderType;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.example.sbsns.oltu.FacebookConfig;
import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
@RequestMapping(value = "/facebook")
public class FacebookOAuthController {
  private static Logger logger = LoggerFactory.getLogger(FacebookOAuthController.class);

  @Autowired
  private FacebookConfig config;

  private static final String REDIRECT_URI = "http://localhost:9000/facebook/callback";

  @RequestMapping(value = "/signin", method = RequestMethod.GET)
  public void signin(
      HttpServletRequest request,
      HttpServletResponse response,
      Model model) throws IOException, OAuthSystemException {
    logger.info("signin");

    String state = "abc123xyz456";

    OAuthClientRequest clientRequest = OAuthClientRequest
        .authorizationProvider(OAuthProviderType.FACEBOOK)
        .setClientId(config.getAppID())
        .setRedirectURI(REDIRECT_URI)
        .setResponseType("code")
        .setScope("public_profile,user_friends,user_birthday,email,user_photos,user_about_me")
        .setState(state)
        .buildQueryMessage();

    String redirectURL = clientRequest.getLocationUri();
    logger.info("redirectURL:{}", redirectURL);

    response.sendRedirect(clientRequest.getLocationUri());
  }

  @RequestMapping(value = "/callback", method = RequestMethod.GET)
  public String callback(
      FacebookOAuthCallbackForm form,
      HttpServletRequest request,
      HttpServletResponse response,
      Model model) throws OAuthProblemException, OAuthSystemException {
    logger.info("callback");
    logger.info("form:{}", form);

    String code;
    String state;
    try {
      OAuthAuthzResponse oar = OAuthAuthzResponse.oauthCodeAuthzResponse(request);
      code = oar.getCode();
      state = oar.getState();
      logger.info("code:{}",code);
      logger.info("state:{}",state);
    } catch (OAuthProblemException e) {
      logger.error("OAuth response error", e);
      return "redirect:/";
    }

    OAuthClientRequest oauthRequest = OAuthClientRequest
        .tokenProvider(OAuthProviderType.FACEBOOK)
        .setClientId(config.getAppID())
        .setClientSecret(config.getAppSecret())
        .setRedirectURI(REDIRECT_URI)
        .setGrantType(GrantType.AUTHORIZATION_CODE)
        .setCode(code)
        .buildBodyMessage();

    OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
    GitHubTokenResponse oAuthResponse = oAuthClient.accessToken(oauthRequest, GitHubTokenResponse.class);

    String accessToken = oAuthResponse.getAccessToken();
    String scope = oAuthResponse.getScope();
    String expiresIn = oAuthResponse.getParam("expires");

    logger.info("oAuthResponse:{}", oAuthResponse.toString());
    logger.info("accessToken:{}",accessToken);
    logger.info("scope:{}",scope);
    logger.info("expire:{}",expiresIn);

    request.getSession().setAttribute("accessToken", accessToken);

    return "facebook/callback";
  }

  @RequestMapping(value = "/user", method = RequestMethod.GET)
  public String user(
      HttpServletRequest request,
      HttpServletResponse response,
      Model model) throws OAuthSystemException, OAuthProblemException {
    logger.info("user");

    String accessToken = (String) request.getSession().getAttribute("accessToken");

    OAuthClientRequest bearerClientRequest =
        new OAuthBearerClientRequest("https://graph.facebook.com/me?fields=id,first_name,last_name,picture,email")
            .setAccessToken(accessToken)
            .buildQueryMessage();

    OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
    OAuthResourceResponse resourceResponse = oAuthClient.resource(bearerClientRequest, "GET", OAuthResourceResponse.class);
    String userinfoJSON = resourceResponse.getBody();
    logger.info("json:{}", userinfoJSON);

    try {
      FacebookUserProfile userProfile = new ObjectMapper().readValue(userinfoJSON, FacebookUserProfile.class);
      request.getSession().setAttribute("facebookId", userProfile.getId());
      model.addAttribute("userProfile", userProfile);
      logger.info("{}", userProfile.toString());
    } catch (IOException e) {
      logger.error("Json parse error", e);
      return "redirect:/";
    }

    return "facebook/user";
  }

  @RequestMapping(value = "/signout", method = RequestMethod.GET)
  public String signout(
      HttpServletRequest request,
      HttpServletResponse response,
      Model model) throws IOException, OAuthSystemException, OAuthProblemException {
    logger.info("signout");

    String accessToken = (String) request.getSession().getAttribute("accessToken");
    String facebookId = (String) request.getSession().getAttribute("facebookId");

    OAuthClientRequest bearerClientRequest =
        new OAuthBearerClientRequest("https://graph.facebook.com/" + facebookId + "/permissions")
            .setAccessToken(accessToken)
            .buildQueryMessage();

    OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
    OAuthResourceResponse resourceResponse = oAuthClient.resource(bearerClientRequest, "DELETE", OAuthResourceResponse.class);
    String json = resourceResponse.getBody();
    logger.info("json:{}", json);

    return "index";
  }

}

Response Object

package com.example.sbsns.oltu.web;

import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown=true)
public class FacebookUserProfile implements Serializable {

  private static final long serialVersionUID = 7957841067903054430L;

  @JsonProperty("id")
  private String id;
  @JsonProperty("last_name")
  private String lastName;
  @JsonProperty("first_name")
  private String firstName;
  @JsonProperty("email")
  private String email;
  @JsonProperty("picture")
  private FacebookPicture picture;

  public String getId() {
    return id;
  }
  public void setId(String id) {
    this.id = id;
  }
  public String getLastName() {
    return lastName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public String getFirstName() {
    return firstName;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public String getEmail() {
    return email;
  }
  public void setEmail(String email) {
    this.email = email;
  }
  public FacebookPicture getPicture() {
    return picture;
  }
  public void setPicture(FacebookPicture picture) {
    this.picture = picture;
  }

  @Override
  public String toString() {
    return "FacebookUserProfile [id=" + id + ", lastName=" + lastName
        + ", firstName=" + firstName + ", email=" + email + ", picture="
        + picture + "]";
  }
}
package com.example.sbsns.oltu.web;

import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown=true)
public class FacebookPicture implements Serializable {

  private static final long serialVersionUID = 5591928605444403203L;

  @JsonProperty("data")
  private FacebookPictureData data;

  public FacebookPictureData getData() {
    return data;
  }
  public void setData(FacebookPictureData data) {
    this.data = data;
  }

  @Override
  public String toString() {
    return "FacebookPicture [data=" + data + "]";
  }
}
package com.example.sbsns.oltu.web;

import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown=true)
public class FacebookPictureData implements Serializable {

  private static final long serialVersionUID = -857548118195277215L;

  @JsonProperty("is_silhouette")
  private boolean isSilhouette;
  @JsonProperty("url")
  private String url;

  public boolean isSilhouette() {
    return isSilhouette;
  }
  public void setSilhouette(boolean isSilhouette) {
    this.isSilhouette = isSilhouette;
  }
  public String getUrl() {
    return url;
  }
  public void setUrl(String url) {
    this.url = url;
  }

  @Override
  public String toString() {
    return "FacebookPictureData [isSilhouette=" + isSilhouette + ", url=" + url
        + "]";
  }
}
6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5