OAuth com Facebook e Java

Caros,

Depois de muito bater cabeça e muitos tutoriais depois, consegui criar um projeto que utiliza o protocolo OAuth e a API do Facebook para efetuar login em uma aplicação Web. Curtam o tutorial.

O que eu utilizei:

  • Netbeans 7.1.2
  • Java 7
  • Facebook-api-3.0.4
  • Primefaces 3.3.1
  • RestFb 1.6.9
  • Maven
  • Glassfish 3.1.2
  • JSF 2

Passo 1.

Crie um projeto web Maven através do menu: Arquivo -> Novo Projeto -> Maven -> Aplicação Web. Siga os passos selecionando o Glassfish e afins (não entrarei no cerne da criação de um projeto web).

Passo 2.

Edite o arquivo pom.xml adicionando os seguintes repositórios e dependências:


<repositories>
<repository>
<id>prime-repo</id>
<name>PrimeFaces Maven Repository</name>
<url>http://repository.primefaces.org</url>
<layout>default</layout>
</repository>
</repositories>


<dependencies>
<dependency>
<groupId>com.restfb</groupId>
<artifactId>restfb</artifactId>
<version>1.6.9</version>
</dependency>
<dependency>
<groupId>com.google.code.facebookapi</groupId>
<artifactId>facebook-java-api</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>freemaker</groupId>
<artifactId>freemaker</artifactId>
<version>2.3.8</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>br.com.xpert</groupId>
<artifactId>xpertframework</artifactId>
<version>1.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-api</artifactId>
<version>2.10</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>3.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

Passo 3. Crie uma Classe chamada UsuarioFB, essa classe irá armazenar os dados provindos do Facebook:


public class Usuario {

@Facebook
private String id;
@Facebook
private String name;
@Facebook
private String email;

A Anotação @Facebook provém do RestFB, um biblioteca que encontrei nas minhas pesquisas na web e muito me ajudou. Mais informações em: RestFB.com

Passo 4. Crie um ManagedBean que irá gerenciar o usuário logado da aplicação:


@ManagedBean
@SessionScoped
public class LoginController {

private String login;
private String senha;
private Usuario usuario;

Observação!!! Nunca se esqueça de implementar os métodos getters e setters!!!

Passo 4. Configure sua aplicação no Facebook, para isso acesse o link: Facebook Developers. Tutorial bom: Tutorial Configuração Aplicação. Esse passo irá gerar uma API_KEY e uma API_SECRET.

Passo 5. Crie um Classe chamada FaceBookClient que irá gerir os métodos de conexão e obtenção do token de acesso:


public class FaceBookClient {

public static String API_KEY = “SUA API KEY”;
public static String SECRET = “SUA API SECRET”;
private static final String client_id = “SEU CLIENT ID”;
// set this to your servlet URL for the authentication servlet/filter
private static final String redirect_uri = “SUA URL DE RETORNO (pode ser o locahost)”;
/// set this to the list of extended permissions you want
private static final String[] perms = new String[]{“publish_stream”, “email”};

public static String getAPIKey() {
return API_KEY;
}

public static String getSecret() {
return SECRET;
}

public static String getLoginRedirectURL() {
return “https://graph.facebook.com/oauth/authorize?client_id=&#8221;
+ API_KEY + “&display=page&redirect_uri=”
+ redirect_uri + “&scope=publish_stream, email”;
}

public static String getAuthURL(String authCode) {
return “https://graph.facebook.com/oauth/access_token?client_id=&#8221;
+ API_KEY + “&redirect_uri=”
+ redirect_uri + “&client_secret=” + SECRET + “&code=” + authCode;
}

Passo 6. Implementaremos agora um Filter que irá receber a resposta do Facebook.


public class FacebookFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
}

@Override
public void doFilter(ServletRequest sr, ServletResponse sr1, FilterChain fc) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) sr;
HttpServletResponse res = (HttpServletResponse) sr1;
String code = sr.getParameter(“code”);

if (code != “”) {
String authURL = FaceBookClient.getAuthURL(code);
URL url = new URL(authURL);
try {
String result = readURL(url);
String accessToken = null;
Integer expires = null;
String[] pairs = result.split(“&”);
for (String pair : pairs) {
String[] kv = pair.split(“=”);
if (kv.length != 2) {
throw new RuntimeException(“Unexpected auth response”);
} else {
if (kv[0].equals(“access_token”)) {
accessToken = kv[1];
}
if (kv[0].equals(“expires”)) {
expires = Integer.valueOf(kv[1]);
}
}
}
if (accessToken != null && expires != null) {

Usuario u = new Usuario();
UsuarioService us = new UsuarioService();
us.authFacebookLogin(accessToken, expires);
res.sendRedirect(“AQUI COLOQUE A URL DE RETORNO depois do login, por exemplo: http://localhost:8080/LoginFacebook/logado.jsf&#8221;);
} else {
throw new RuntimeException(“Access token and expires not found”);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

private String readURL(URL url) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = url.openStream();
int r;
while ((r = is.read()) != -1) {
baos.write(r);
}
return new String(baos.toByteArray());
}

@Override
public void destroy() {
}
}

Passo 7. Configure o Filter no web.xml:

<filter>
<filter-name>FacebookFilter</filter-name>
<filter-class>br.com.estudos.filter.FacebookFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FacebookFilter</filter-name>
<url-pattern>/login/*</url-pattern>
</filter-mapping>

Passo 8. Implementemos agora o método que efetua o login no ManagedBean, adicione o seguinte código no ManagedBean:

public String conectarComFace() {
return FaceBookClient.getLoginRedirectURL();
}

Passo 9. Perceba que na configuração do Filter colocamos para ele atuar em um diretório chamado login, isso força nossa implementação a url de redirecionamento (configurada no passo 5) ser redirecionada para uma página dentro desse diretório. Portanto, crie esse diretório na sua aplicação.

Passo 10. Crie as páginas para efetuar o Login que deve conter um commandLink:

<h:outputLink value=”#{loginController.conectarComFace()}”>
Login com FaceBook
</h:outputLink>

A página logado (como configurado no passo 6) contém apenas a palavra `Logado`.

Passo 11. Criaremos um UsuarioService, reponsável pela consulta dos dados do usuário:


public class UsuarioService {

public void authFacebookLogin(String accessToken, int expires) {
try {

FacebookClient fb = new DefaultFacebookClient(accessToken);

Usuario user = fb.fetchObject(“me”, Usuario.class);

System.out.println(user);

} catch (Throwable ex) {
throw new RuntimeException(“failed login”, ex);
}
}
}

O código do exemplo está aqui: LoginFacebook!

Enjoy!