javascript
spring social_Spring Social入门–第2部分
spring social
幾周前,我寫了一篇文章,展示了我認(rèn)為可以使用Spring Social編寫的最簡(jiǎn)單的應(yīng)用程序。 該應(yīng)用程序讀取并顯示了Twitter用戶的公共數(shù)據(jù),并被編寫為Spring Social和社交編碼領(lǐng)域的介紹。 但是,讓您的應(yīng)用程序顯示用戶的公共數(shù)據(jù)只是故事的一半,而且在大多數(shù)情況下,您將需要顯示用戶的私有數(shù)據(jù)。在本博客中,我將介紹您需要在應(yīng)用程序的一兩個(gè)頁面上顯示用戶的Facebook或其他軟件即服務(wù)(SaaS)提供程序數(shù)據(jù)的情況。 這里的想法是嘗試演示最小的和最簡(jiǎn)單的操作,您可以將Spring Social添加到需要用戶登錄Facebook或其他SaaS提供商的應(yīng)用程序中。
創(chuàng)建應(yīng)用
要?jiǎng)?chuàng)建該應(yīng)用程序,第一步是使用SpringSource Toolkit儀表板的模板部分創(chuàng)建一個(gè)基本的Spring MVC項(xiàng)目。 這提供了一個(gè)Web應(yīng)用程序,可幫助您入門。
下一步是通過添加以下依賴項(xiàng)來設(shè)置pom.xml :
<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-crypto</artifactId><version>${org.springframework.security.crypto-version}</version> </dependency><!-- Spring Social --> <dependency><groupId>org.springframework.social</groupId><artifactId>spring-social-core</artifactId><version>${spring-social.version}</version> </dependency> <dependency><groupId>org.springframework.social</groupId><artifactId>spring-social-web</artifactId><version>${spring-social.version}</version> </dependency><!-- Facebook API --> <dependency><groupId>org.springframework.social</groupId><artifactId>spring-social-facebook</artifactId><version>${org.springframework.social-facebook-version}</version> </dependency><!-- JdbcUserConfiguration --> <dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${org.springframework-version}</version> </dependency> <dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><version>1.3.159</version> </dependency><!-- CGLIB, only required and used for @Configuration usage: could be removed in future release of Spring --> <dependency><groupId>cglib</groupId><artifactId>cglib-nodep</artifactId><version>2.2</version> </dependency>…顯然,您還需要在文件的%lt; properties />部分中添加以下內(nèi)容:
<spring-social.version>1.0.2.RELEASE</spring-social.version> <org.springframework.social-facebook-version>1.0.1.RELEASE</org.springframework.social-facebook-version> <org.springframework.security.crypto-version>3.1.0.RELEASE</org.springframework.security.crypto-version>您會(huì)注意到,我為spring-security-crypto添加了一個(gè)特定的pom條目:這是因?yàn)槲艺谑褂肧pring 3.0.6。 在Spring 3.1.x中,它已成為核心庫的一部分。
唯一要注意的一點(diǎn)是,還依賴于spring-jdbc和h2 。 這是因?yàn)镾pring的UserConnectionRepository默認(rèn)實(shí)現(xiàn): JdbcUsersConnectionRepository使用它們,因此即使此應(yīng)用程序不對(duì)數(shù)據(jù)庫持久化任何東西(據(jù)我所知),它們也是必需的。
班級(jí)
社交編碼功能包括四個(gè)類(其中一個(gè)是我從Keith Donald的Spring Social Quick Start Sample代碼中摘錄的):
- FacebookPostsController
- 社會(huì)背景
- Facebook配置
- UserCookieGenerator
FacebookPostsController是應(yīng)用程序的業(yè)務(wù)端,負(fù)責(zé)獲取用戶的Facebook數(shù)據(jù)并將其推入模型中以供顯示。
@Controllerpublic class FacebookPostsController {private static final Logger logger = LoggerFactory.getLogger(FacebookPostsController.class);private final SocialContext socialContext;@Autowiredpublic FacebookPostsController(SocialContext socialContext) {this.socialContext = socialContext;}@RequestMapping(value = 'posts', method = RequestMethod.GET)public String showPostsForUser(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {String nextView;if (socialContext.isSignedIn(request, response)) {List<Post> posts = retrievePosts();model.addAttribute('posts', posts);nextView = 'show-posts';} else {nextView = 'signin';}return nextView;}private List<Post> retrievePosts() {Facebook facebook = socialContext.getFacebook();FeedOperations feedOps = facebook.feedOperations();List<Post> posts = feedOps.getHomeFeed();logger.info('Retrieved ' + posts.size() + ' posts from the Facebook authenticated user');return posts;}}如您所見,從高級(jí)的角度來看,我們要實(shí)現(xiàn)的目標(biāo)的邏輯非常簡(jiǎn)單:
IF user is signed in THEN read Facebook data, display Facebook data ELSE ask user to sign in when user has signed in, go back to the beginning END IFFacebookPostsController將處理登錄邏輯的任務(wù)委托給SocialContext類。 您可能會(huì)猜到,我從Spring真正有用的ApplicationContext中得到了此類的想法。 這里的想法是,有一個(gè)類負(fù)責(zé)將您的應(yīng)用程序粘貼到Spring Social。
public class SocialContext implements ConnectionSignUp, SignInAdapter {/*** Use a random number generator to generate IDs to avoid cookie clashes* between server restarts*/private static Random rand;/*** Manage cookies - Use cookies to remember state between calls to the* server(s)*/private final UserCookieGenerator userCookieGenerator;/** Store the user id between calls to the server */private static final ThreadLocal<String> currentUser = new ThreadLocal<String>();private final UsersConnectionRepository connectionRepository;private final Facebook facebook;public SocialContext(UsersConnectionRepository connectionRepository, UserCookieGenerator userCookieGenerator,Facebook facebook) {this.connectionRepository = connectionRepository;this.userCookieGenerator = userCookieGenerator;this.facebook = facebook;rand = new Random(Calendar.getInstance().getTimeInMillis());}@Overridepublic String signIn(String userId, Connection<?> connection, NativeWebRequest request) {userCookieGenerator.addCookie(userId, request.getNativeResponse(HttpServletResponse.class));return null;}@Overridepublic String execute(Connection<?> connection) {return Long.toString(rand.nextLong());}public boolean isSignedIn(HttpServletRequest request, HttpServletResponse response) {boolean retVal = false;String userId = userCookieGenerator.readCookieValue(request);if (isValidId(userId)) {if (isConnectedFacebookUser(userId)) {retVal = true;} else {userCookieGenerator.removeCookie(response);}}currentUser.set(userId);return retVal;}private boolean isValidId(String id) {return isNotNull(id) && (id.length() > 0);}private boolean isNotNull(Object obj) {return obj != null;}private boolean isConnectedFacebookUser(String userId) {ConnectionRepository connectionRepo = connectionRepository.createConnectionRepository(userId);Connection<Facebook> facebookConnection = connectionRepo.findPrimaryConnection(Facebook.class);return facebookConnection != null;}public String getUserId() {return currentUser.get();}public Facebook getFacebook() {return facebook;}}SocialContext實(shí)現(xiàn)Spring Social的ConnectionSignUp和SignInAdapter接口。 它包含三個(gè)方法isSignedIn() , signIn() , execute() 。 FacebookSignsController類調(diào)用isSignedIn來實(shí)現(xiàn)上述邏輯,而Spring Social調(diào)用signIn()和execute() 。
從我以前的博客中,您會(huì)記住,OAuth需要在瀏覽器,您的應(yīng)用程序和SaaS提供程序之間進(jìn)行多次旅行。 在進(jìn)行這些操作時(shí),應(yīng)用程序需要保存多個(gè)OAuth參數(shù)的狀態(tài),例如:client_id,redirect_uri和其他參數(shù)。 通過將OAuth對(duì)話的狀態(tài)映射到您的Webapp所控制的變量,Spring Social將所有這些復(fù)雜性從應(yīng)用程序中隱藏起來。 這是userId ; 但是,不要以為它是用戶名,因?yàn)樗鼜奈幢挥脩艨吹?#xff0c;它只是一個(gè)唯一標(biāo)識(shí)符,該標(biāo)識(shí)符將許多HTTP請(qǐng)求鏈接到Spring Social核心中的SaaS提供程序連接(例如Facebook)。
由于其簡(jiǎn)單性,我遵循了Keith Donald的想法,即使用cookie在瀏覽器和服務(wù)器之間傳遞用戶ID來保持狀態(tài)。 我還從Spring Social快速入門中借用了他的UserCookieGenerator類來幫助我。
isSignedIn(...)方法使用UserCookieGenerator來確定HttpServletRequest對(duì)象是否包含包含有效用戶ID的cookie。 如果這樣做的話,它還會(huì)找出Spring Social的UsersConnectionRepository是否包含鏈接到相同用戶ID的ConnectionRepository 。 如果這兩個(gè)測(cè)試都返回true,則應(yīng)用程序?qū)⒄?qǐng)求并顯示用戶的Facebook數(shù)據(jù)。 如果兩個(gè)測(cè)試之一返回false,則將要求用戶登錄。
SocialContext是專門為該示例編寫的,并且包含足夠的功能來演示我在此博客中所討論的內(nèi)容。 這意味著它目前有點(diǎn)粗糙并且可以使用,盡管可以對(duì)其進(jìn)行改進(jìn)以涵蓋與任何/許多提供程序的連接,然后在不同的應(yīng)用程序中重復(fù)使用。
最后要提到的類是FacebookConfig ,它大致基于Spring Social示例代碼。 此代碼與示例代碼之間有兩個(gè)主要區(qū)別,其中一個(gè)是FacebookConfig類實(shí)現(xiàn)InitializingBean接口。 這樣,可以將usersConnectionRepositiory變量注入到socialContext中, 然后可以將socialContext作為其ConnectionSignUp實(shí)現(xiàn)注入到usersConnectionRepositiory中。 第二個(gè)區(qū)別是我正在實(shí)現(xiàn)providerSignInController(...)方法,以提供正確配置的ProviderSignInController對(duì)象,Spring Social將使用該對(duì)象登錄Facebook。 我在此處所做的默認(rèn)設(shè)置的唯一更改是將ProviderSignInController的postSignInUrl屬性設(shè)置為“ / posts ”。 這是頁面的URL,將包含用戶Facebook數(shù)據(jù),并在用戶登錄完成后被調(diào)用。
@Configurationpublic class FacebookConfig implements InitializingBean {private static final Logger logger = LoggerFactory.getLogger(FacebookConfig.class);private static final String appId = '439291719425239';private static final String appSecret = '65646c3846ab46f0b44d73bb26087f06';private SocialContext socialContext;private UsersConnectionRepository usersConnectionRepositiory;@Injectprivate DataSource dataSource;/*** Point to note: the name of the bean is either the name of the method* 'socialContext' or can be set by an attribute* * @Bean(name='myBean')*/@Beanpublic SocialContext socialContext() {return socialContext;}@Beanpublic ConnectionFactoryLocator connectionFactoryLocator() {logger.info('getting connectionFactoryLocator');ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();registry.addConnectionFactory(new FacebookConnectionFactory(appId, appSecret));return registry;}/*** Singleton data access object providing access to connections across all* users.*/@Beanpublic UsersConnectionRepository usersConnectionRepository() {return usersConnectionRepositiory;}/*** Request-scoped data access object providing access to the current user's* connections.*/@Bean@Scope(value = 'request', proxyMode = ScopedProxyMode.INTERFACES)public ConnectionRepository connectionRepository() {String userId = socialContext.getUserId();logger.info('Createung ConnectionRepository for user: ' + userId);return usersConnectionRepository().createConnectionRepository(userId);}/*** A proxy to a request-scoped object representing the current user's* primary Facebook account.* * @throws NotConnectedException* if the user is not connected to facebook.*/@Bean@Scope(value = 'request', proxyMode = ScopedProxyMode.INTERFACES)public Facebook facebook() {return connectionRepository().getPrimaryConnection(Facebook.class).getApi();}/*** Create the ProviderSignInController that handles the OAuth2 stuff and* tell it to redirect back to /posts once sign in has completed*/@Beanpublic ProviderSignInController providerSignInController() {ProviderSignInController providerSigninController = new ProviderSignInController(connectionFactoryLocator(),usersConnectionRepository(), socialContext);providerSigninController.setPostSignInUrl('/posts');return providerSigninController;}@Overridepublic void afterPropertiesSet() throws Exception {JdbcUsersConnectionRepository usersConnectionRepositiory = new JdbcUsersConnectionRepository(dataSource,connectionFactoryLocator(), Encryptors.noOpText());socialContext = new SocialContext(usersConnectionRepositiory, new UserCookieGenerator(), facebook());usersConnectionRepositiory.setConnectionSignUp(socialContext);this.usersConnectionRepositiory = usersConnectionRepositiory;}}申請(qǐng)流程
如果您運(yùn)行此應(yīng)用程序2,首先會(huì)看到一個(gè)主屏幕,其中包含一個(gè)簡(jiǎn)單的鏈接,邀請(qǐng)您顯示帖子。 首次單擊此鏈接時(shí),您將重定向到/ signin頁面。 按下“登錄”按鈕,指示ProviderSignInController與Facebook聯(lián)系。 身份驗(yàn)證完成后, ProviderSignInController會(huì)將應(yīng)用程序定向回/ posts頁面,這一次它將顯示Facebook數(shù)據(jù)。
組態(tài)
為了完整起見,我認(rèn)為我應(yīng)該提到XML配置,盡管它沒有太多,因?yàn)槲以贔acebookConfig類上使用了Spring注釋@Configuration 。 我已經(jīng)從Spring Social導(dǎo)入了“ data.xml ”,以便JdbcUsersConnectionRepository可以工作并添加了
<context:component-scan base-package='com.captaindebug.social' />…用于自動(dòng)接線。
摘要
盡管此示例應(yīng)用程序基于將應(yīng)用程序連接到用戶的Facebook數(shù)據(jù)的基礎(chǔ),但可以輕松地對(duì)其進(jìn)行修改以使用任何Spring Social客戶端模塊。 如果您喜歡挑戰(zhàn),請(qǐng)嘗試在所有中文版本的地方實(shí)施Sina-Weibo-這是一個(gè)挑戰(zhàn),但是Google Translate確實(shí)很有用。
1個(gè)Spring社交和其他OAuth博客:
2該代碼可在Github上找到:https://github.com/roghughe/captaindebug.git
參考: Captain Debug的Blog博客中的JCG合作伙伴 Roger Hughes的Spring Social入門-第2部分 。
翻譯自: https://www.javacodegeeks.com/2012/07/getting-started-with-spring-social-part.html
spring social
總結(jié)
以上是生活随笔為你收集整理的spring social_Spring Social入门–第2部分的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 匪的组词 匪的组词有哪些
- 下一篇: ejb jsf jpa_完整的WebAp