How to do it...
- 模仿之前的步骤,在Facebook创建一个新项目social- authcode 。输入网址地址:还有授权成功后的,重定向的地址::8080/connect/facebook
- 新建一个Spring项目 在 网址新建一个项目,加入web,thymeleaf模块。
-
在
pom.xml
文件加入以下依赖:org.springframework.boot spring-boot-starter-thymeleaf 1.5.10.RELEASE org.springframework.boot spring-boot-starter-web 1.5.10.RELEASE org.springframework.boot spring-boot-starter-test 1.5.10.RELEASE test org.springframework.social spring-social-config 1.1.6.RELEASE org.springframework.social spring-social-facebook 2.0.3.RELEASE org.springframework.boot spring-boot-autoconfigure 1.5.10.RELEASE - 在src/main/resources文件夹创建
friends.html文件:
Friends Hello,User!
Your friends which also allowed social-authcode:
[id] - [name]
5.新建FriendsController.java
,映射friends.html
页面,其中ConnectionRepository存储或重定向与某个OAuth2.0 provider的连接,目前是只展示了Facebook。
//FriendsController.java@Controller@RequestMapping("/")public class FriendsController { @Autowired private Facebook facebook; @Autowired private ConnectionRepository connectionRepository; //链接上一步的html, @GetMapping public String friends(Model model) { //如果没有获取授权,则跳到申请授权页面 if (connectionRepository.findPrimaryConnection(Facebook.class)== null) { //就返回这个链接 return "redirect:/connect/facebook"; } //如果已拿到授权,就从facebook获取用户和联系人信息,传给friends.html String [] fields = { "id", "email", "name" }; //获取用户信息 User userProfile = facebook.fetchObject("me", User.class, fields); model.addAttribute("facebookProfile", userProfile); //获取联系人信息 PagedListfriends =facebook.friendOperations().getFriends(); model.addAttribute("friends", friends); return "friends";}}
6.上述步骤通过授权码模式,完成了从Facebook获取用户信息和联系人信息的大致过程。但是,我们还需创建一些配置类,为了更好得管理这些配置类,我们新建一个名为facebook的package,这些是我们所需的配置类:
7.创建EnhancedFacebookProperties 类,加载client_id,client_secret,还有版本号,并把这些内容写入application.properties
//EnhancedFacebookProperties.java@Component@ConfigurationProperties(prefix = "facebook")public class EnhancedFacebookProperties {private String appId;private String appSecret;private String apiVersion;// getters and setters omitted for brevity}//application.propertiesfacebook.app-id=1948923582021549facebook.app-secret=1b4b0f882b185094a903e76a661c7c7cfacebook.api-version=2.9
8.创建CustomFacebookServiceProvider 类,用于创建一个OAuth2Template 实例
//CustomFacebookServiceProvider.javapublic class CustomFacebookServiceProvider extends AbstractOAuth2ServiceProvider{ private String appNamespace; private String apiVersion; public CustomFacebookServiceProvider(String appId, String appSecret, String apiVersion) { super(getOAuth2Template(appId, appSecret, apiVersion)); this.apiVersion = apiVersion; } private static OAuth2Template getOAuth2Template(String appId, String appSecret, String apiVersion) { String graphApiURL = "https://graph.facebook.com/v" + apiVersion + "/"; OAuth2Template template = new OAuth2Template(appId, appSecret, "https://www.facebook.com/v" +apiVersion + "/dialog/oauth", graphApiURL + "oauth/access_token"); template.setUseParametersForClientAuthentication(true); return template; } @Override public Facebook getApi(String accessToken) { FacebookTemplate template = new FacebookTemplate(accessToken,appNamespace); template.setApiVersion(apiVersion); return template; }}
9.创建CustomFacebookConnectionFactory 类
//CustomFacebookConnectionFactory public class CustomFacebookConnectionFactory extends OAuth2ConnectionFactory{ public CustomFacebookConnectionFactory(String appId, String appSecret, String apiVersion) { super("facebook",new CustomFacebookServiceProvider(appId, appSecret, apiVersion),new FacebookAdapter()); }}
10.创建FacebookConfiguration 类:
@Configuration@EnableSocial@EnableConfigurationProperties(FacebookProperties.class)public class FacebookConfiguration extends SocialAutoConfigurerAdapter { @Autowired private EnhancedFacebookProperties properties; @Override protected ConnectionFactory createConnectionFactory() { return new CustomFacebookConnectionFactory(this.properties.getAppId(), this.properties.getAppSecret(), this.properties.getApiVersion()); } //提供Facebook 实例 @Bean @ConditionalOnMissingBean(Facebook.class) @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES) public Facebook facebook(ConnectionRepository repository) { Connectionconnection = repository.findPrimaryConnection(Facebook.class); return connection != null ? connection.getApi() : null; } //当我们使用spring social的时候,我们会使用ConnectController 类来处理重定向的问题。默认情况下,spring social会根据request URL ,自动构造redirect URL,因为这个应用程序可能藏在代理下,provider没办法识别url,因此,我们在这里手动输入 @Bean public ConnectController connectController(ConnectionFactoryLocator factoryLocator, ConnectionRepository repository) { ConnectController controller = new ConnectController(factoryLocator, repository); controller.setApplicationUrl("https://localhost:8080"); return controller; }}
11.在之前构造的FriendsController
,已经完成了几乎所有的OAuth2 验证流程,但是我们还需要编写两个html文件来完成两个页面的加载,这两个页面是我们需要提供{provider}Connect 和{provider}Connected ,在本例中,是Facebook。因而,在templates/connect/文件夹新建2个文件:facebookConnect.html
,facebookConnected.html
,并填入以下代码:
//facebookConnected.htmlSocial Authcode Connected to Facebook
Click here to see your friends.
//facebookConnect.htmlSocial Authcode Connect to Facebook to see your contacts
How it works…
这一章展示了,怎样去注册应用,怎样通过Authorization Code type(授权码) 模式,来连接facebook.由于是server端的连接,比起client端的连接方式(implict grant type)更加安全。我们使用Spring Social来完成social-authcode和Facebook的会话。Spring Social提供ConnectController类来开启会话流程,处理返回数据,因而,我们也要提供页面来接收这些数据。为了
There's more…
当我们在Facebook注册了应用后,将redirect url配置为:8080/connect,为什么不使用:8080/callback?因为ConnectController可以处理/connect的endpoint,如果你不想使用Spring Social,你将要自己来验证授权码.
尽管,我们使用了Spring Social Facebook,我们依然创建了一些以“Custom”开头的类。通过这些类,我们可以定制化OAuth2Template和FacebookTemplate 实例的构建,这很重要,因为当前的FacebookTemplate 版本,可以支持这样的定制。
此外,在客户端和OAuth 2.0 Provider 的交互过程中,我们没有使用TLS/SSL,注册地址我们使用的是HTTP而非HTTPS,书中的例子是为了简单展示,才简化过程。但是在生产环境中,请使用HTTPs来保护数据。
另一件有价值的事,是使用关系数据库管理系统,来持久化你与Provider的连接,我们之前将连接保存在内存中,这意味着,一旦我们重启服务,连接就会丢失。如果你想使用数据库,那么你可能需要定义一个bean“JdbcUsersConnectionRepository ”,并且在数据库,通过如下命令构建表:
create table UserConnection (userId varchar(255) not null,providerId varchar(255) not null,providerUserId varchar(255),rank int not null,displayName varchar(255),profileUrl varchar(512),imageUrl varchar(512),accessToken varchar(512) not null,secret varchar(512),refreshToken varchar(512),expireTime bigint,primary key (userId, providerId, providerUserId));create unique index UserConnectionRank on UserConnection(userId,providerId, rank);