vlambda博客
学习文章列表

读书笔记《spring-security-3-x-cookbook》Spring Security 与 Spring Social 访问 Twitter

第 9 章 Spring Security 与 Spring Social

在本章中,我们将介绍:

  • Spring Security 与 Spring Social 访问 Facebook

  • Spring Security 与 Spring Social 访问 Twitter

  • 具有多个身份验证提供程序的 Spring Security

  • 使用 OAuth 的 Spring 安全性

介绍


Spring Social 是一个著名的 API。大多数 Web 应用程序都希望用户可以选择从他们的应用程序发布到 Facebook 和 Twitter 等社交网站。 Spring Social 就是为满足这一要求而构建的。

在本章中,我们将 Spring Security 与 Spring Social 集成以连接到 Facebook 和 Twitter 帐户。

Spring Security 与 Spring Social 访问 Facebook


对于 身份验证,Spring Social 使用 spring -安全 API。我们需要在 pom.xml 中添加 spring-social 依赖以及 spring-corespring-security 包。在本节中,我们将演示 Spring Social 如何将我们的 java 应用程序连接到 Facebook。我们可以在我们的 java 应用程序中登录 Facebook 应用程序。

一旦与社交网站建立连接,用户就可以从中发布和检索消息。

我们使用了相同的休眠恐怖电影应用程序。我使用了 derby 数据库,并且 在 glassfish 服务器上部署了应用程序。 Spring Social 内部使用 Spring 的 jdbctemplate 类来检索数据库信息。

准备好

您需要执行以下任务才能使用 Spring Security 和 Spring Social 访问 Facebook:

  • 注册为 Facebook 开发者并创建应用程序。您将获得可用于集成的 appID 和密钥

  • 将请求映射添加到控制器以处理 Facebook 创建的 jsp 页面以将消息发布到 Facebook

  • 创建 UserConnection

  • 将 Jackson 依赖项添加到您的 pom.xml 文件中。演示项目可随本书一起下载

  • 添加 Spring Social 依赖项,例如:

    • Spring-social-core

    • Spring-social-web

    • Spring-social-facebook

    • Spring-social-twitter

    • Spring-social-linkedin

    • Spring-social-github

  • 创建 .jsp 页面供用户登录和注销

  • spring.properties 文件中提供数据库连接属性

  • jdbc.properties 文件中提供 Facebook 的应用程序密钥和 appID

怎么做...

以下是实现允许用户使用 Spring Social 和 Spring Security 登录 Facebook 应用程序的应用程序的步骤:

  1. 创建一个名为 MyController 的控制器来处理 Facebook 页面。

      @RequestMapping(value = "/fbprofile", method = RequestMethod.GET)
      public String getfbProfile(ModelMap model,HttpServletRequest request, 
          HttpServletResponse response) {
        model.addAttribute("request.userPrincipal.name", request.getUserPrincipal().getName());
        Facebook facebook = connectionRepository.getPrimaryConnection(Facebook.class).getApi();
        model.addAttribute("profileLink", facebook.userOperations().getUserProfile().getLink());
        model.addAttribute("Gender", facebook.userOperations().getUserProfile().getGender());
        model.addAttribute("profileInfo", facebook.userOperations().getUserProfile());
        model.addAttribute("userpermissions", facebook.userOperations().getUserPermissions());
        List<Reference> friends = facebook.friendOperations().getFriends();
        model.addAttribute("friends", friends);
        model.addAttribute("friendlist", facebook.friendOperations().getFriendLists());
        return "facebookprofile";
      }
  2. Spring-中提供连接工厂- social.xml 文件:

      <bean id="connectionFactoryLocator" class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
        <property name="connectionFactories">
          <list>
            <bean class="org.springframework.social.facebook.connect.FacebookConnectionFactory">
              <constructor-arg value="${facebook.clientId}" />
              <constructor-arg value="${facebook.clientSecret}" />
            </bean>
          </list>
        </property>
      </bean>

    ConnectionFactory 定位器创建 Facebook bean。您可以在此处添加其他社交网络提供商,例如 Digg 和 Flickr。 UsersConnectionRepository 使用 JDBC 模板执行查询以连接各种社交网络提供商。

  3. 使用 spring-social.xml 文件中的连接工厂:

      <bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors" factory-method="noOpText" />
      <bean id="usersConnectionRepository" class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository">
        <constructor-arg ref="mydataSource" />
        <constructor-arg ref="connectionFactoryLocator" />
        <constructor-arg ref="textEncryptor" />
      </bean>
      <bean id="connectionRepository" factory-method="createConnectionRepository" factory-bean="usersConnectionRepository" scope="request">
          <constructor-arg value="#{request.userPrincipal.name}" />
          <aop:scoped-proxy proxy-target-class="false"/>
      </bean>
  4. ConnectController类 > spring-social 文件。 ConnectController 类在连接到提供者方面起着重要作用。它使用 (/connect) URL 进行映射。为了充分利用 ConnectController 类,为 Facebook 和 Twitter 创建单独的文件夹。

      <bean class="org.springframework.social.connect.web.ConnectController" p:applicationUrl="${application.url}"/>
  5. 在 derby 数据库中运行 SQL 命令。

    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(255) not null,
      secret varchar(255),
      refreshToken varchar(255),
      expireTime bigint,
      primary key (userId, providerId, providerUserId));
    
    create unique index UserConnectionRank on UserConnection(userId, providerId, rank);

这个怎么运作...

Spring Social使用UserConnection表来< /a>将网络站点提供者信息与用户信息一起存储。 Spring Social 使用 Spring Security 以及 appID 和密钥对用户进行身份验证。

访问网址:http://localhost:8080/horrormovie/list

您将被重定向到 http://localhost:8080/horrormovie/login;jsessionid=581813e14c1752d2260521830d3d

使用用户名和密码登录。您将连接到 horromovie 数据库,如以下屏幕截图所示:

读书笔记《spring-security-3-x-cookbook》Spring Security 与 Spring Social 访问 Twitter

点击 Connect to Facebook profile 链接,用户将被重定向到以下网页:

读书笔记《spring-security-3-x-cookbook》Spring Security 与 Spring Social 访问 Twitter

该页面显示以下字段:

  • 个人资料链接

  • 性别

  • 个人资料信息

  • 将消息发布到 Facebook 的文本框

可以从这个应用程序发布消息,然后打开Facebook个人资料查看发布的消息。该消息将以您创建的 Facebook 应用程序的名称发布。

也可以看看

  • Spring Security with Spring Social 访问 Twitter 秘诀

  • 具有多个身份验证提供程序的 Spring Security 配方

  • Spring Security with OAuth 秘诀

Spring Security 与 Spring Social 访问 Twitter


我们刚刚连接了 Facebook,并能够发布消息。在本节中,我们将了解如何连接到 Twitter。让我们使用与 Facebook 相同的应用程序和 derby 数据库并休眠身份验证服务。

准备好

您需要执行以下任务才能使用 Spring Security 通过 Spring Social 访问 Twitter:

  • 创建 Twitter 应用程序:https://dev.twitter.com/apps/new

  • 将使用者 ID 和密钥添加到 .properties 文件。

  • 更新控制器以处理 Twitter 请求

  • 创建 JSP 文件以访问和显示 Twitter 对象

怎么做...

以下 是在演示的应用程序中实现 Twitter 登录选项的步骤在上一节中:

  1. 更新名为 HorrorMovie Controller 的控制器以处理 Twitter 请求。

    < @RequestMapping(value = "/posttofb", method = RequestMethod.GET)
      public String posttofb(String message, ModelMap model) {
        try {
          Facebook facebook = connectionRepository.getPrimaryConnection(Facebook.class).getApi();
          facebook.feedOperations().updateStatus(message);
          model.addAttribute("status", "success");
          model.addAttribute("message", message);
          return "redirect:/list";
        } catch (Exception e) {
          model.addAttribute("status", "failure");
          return "/facebook/fbconnect";
        }
      }
      @RequestMapping(value = "/twprofile", method = RequestMethod.GET)
      public String gettwProfile(ModelMap model) {
        try{
          Twitter twitter = connectionRepository.getPrimaryConnection(Twitter.class).getApi();
          model.addAttribute("twprofileLink", twitter.userOperations().getUserProfile().getUrl());
          model.addAttribute("twprofileInfo", twitter.userOperations().getUserProfile());
          model.addAttribute("twfollowers", twitter.friendOperations().getFollowers());
          model.addAttribute("twfriends", twitter.friendOperations().getFriends());
          return "/twitter/twitterprofile";
        } catch (Exception e) {
          model.addAttribute("status", "failure");
          return "/twitter/twconnect";
        }
      }
      @RequestMapping(value = "/posttotw", method = RequestMethod.GET)
      public String posttotw(String message, ModelMap model) {
        try {
          Twitter twitter = connectionRepository.getPrimaryConnection(Twitter.class).getApi();
          twitter.timelineOperations().updateStatus(message);
          model.addAttribute("status", "success");
          model.addAttribute("message", message);
          return "redirect:/list";
        } catch (Exception e) {
          model.addAttribute("status", "failure");
          return "/twitter/twconnect";
        }
      }

这个怎么运作...

访问 URL:http://localhost:8080/horrormovie/list.

Spring Social 会检查用户是否已经连接到 Twitter。如果用户已经连接,用户将被重定向到 Twitter 页面并被要求登录。Spring Social 使用 Twitter 消费者 ID 和 Spring Security 的密钥从应用程序登录到 Twitter 帐户。这是大多数手机应用程序允许我们登录 Twitter 和 Facebook 的基础。

也可以看看

  • Spring Security with Spring Social 访问 Facebook 秘诀

  • 具有多个身份验证提供程序的 Spring Security 配方

  • Spring Security with OAuth 秘诀

具有多个身份验证提供程序的 Spring Security


这个 部分,我们将演示Spring Social 和数据库的多重身份验证。在我们之前的秘籍中,我们使用了处理 Facebook 和 Twitter 连接的 ConnectController 类。对 Facebook 和 Twitter 的访问仅限于 Spring Security URL,即只有 ROLE_EDITOR 可以访问 Facebook 和 Twitter。用户必须经过身份验证和授权才能使用 Facebook 和 Twitter。在本例中,我们将允许用户使用 Facebook 和 Twitter 或普通用户 ID 登录应用程序。

Craig Walls 是 Spring Social API 的负责人,并在 gitHub 上提供了各种示例,该示例使用 Spring Social 和 Spring Security。这是 Craig Walls 提供的示例之一。

准备好

您将需要执行以下任务:

  1. 创建一个公共页面以作为用户登录或使用 Twitter、Facebook 或链接的个人资料进行注册。

  2. Spring Social API 有一个 ConnectController 类,它会自动查找连接文件夹。创建一个连接文件夹,添加 ${provider}Connect.jsp${provider} Connected.jsp。 $provider{twitter,facebook,linked-in,github}

  3. Spring Social 内部 使用 spring-security。它有自己的用户详细信息类——SocialUserDetailsS​​ervice。创建一个实现 SocialUserDetailsS​​ervice 的类并覆盖该方法。

  4. social-security.xml 文件中配置社交身份验证提供程序。 SocialAuthenticationProvider 类接受两个输入,例如:

    • usersConnectionRepository

    • socialuserDetailsS​​ervice - 实现 SocialUserDetailsS​​ervice 的类

  5. security-xml 中配置多个身份验证提供程序:

    • SocialAuthenticationProvider

    • UserDetailsS​​ervice,jdbc接口,提供用户详细信息服务

  6. 配置过滤器,SocialAuthenticationFilter,用于处理 Spring Security 过滤器链中的提供者登录流程。它应该在 PRE_AUTH_FILTER 位置或之前添加到链中。

怎么做...

以下 是使用 Spring Security 与多个提供者实现身份验证的步骤:

  1. 使用 SocialUsersDetailServiceImpl 类来实现 SocialUserDetailsS​​ervice 类:

    public class SocialUsersDetailServiceImpl implements SocialUserDetailsService {
      private UserDetailsService userDetailsService;
      public SocialUsersDetailServiceImpl(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
      }
      @Override
        public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException, DataAccessException {
        UserDetails userDetails = userDetailsService.loadUserByUsername(userId);
        return new SocialUser(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
      }}
  2. Security.xml 文件中配置类,SocialAuthenticationProvider

      <bean id="socialAuthenticationProvider" class="org.springframework.social.security.SocialAuthenticationProvider" c:_0-ref="usersConnectionRepository" c:_1-ref="socialUsersDetailService" />
      <bean id="socialUsersDetailService" class="org.springframework.social.showcase.security.SocialUsersDetailServiceImpl" c:_-ref="userDetailsService" />
  3. Security.xml 文件中配置多个身份验证 提供程序:

      <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref="userDetailsService">
          <password-encoder ref="passwordEncoder" />
        </authentication-provider>
        <!-- Spring Social Security authentication provider -->
        <authentication-provider ref="socialAuthenticationProvider" />
      </authentication-manager>
      <jdbc-user-service id="userDetailsService" data-source-ref="dataSource" users-by-username-query="select username, password, true from Account where username = ?" authorities-by-username-query="select username, 'ROLE_USER' from Account where username = ?"/>
      <beans:bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors" factory-method="noOpText" />
      <beans:bean id="passwordEncoder" class="org.springframework.security.crypto.password.NoOpPasswordEncoder" factory-method="getInstance" />
  4. Social-security.xml 文件中配置 SocialAuthenticationFilter 类:

    <bean id="socialAuthenticationFilter" class="org.springframework.social.security.SocialAuthenticationFilter" c:_0-ref="authenticationManager" c:_1-ref="userIdSource" c:_2-ref="usersConnectionRepository" c:_3-ref="connectionFactoryLocator" p:signupUrl="/spring-social-showcase/signup" p:rememberMeServices-ref="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices#0" />
  5. 配置 SocialAuthenticationFilter security.xml 文件中的安全性:

    <http use-expressions="true">
        <!-- Authentication policy -->
        <form-login login-page="/signin" login-processing-url="/signin/authenticate" authentication-failure-url="/signin?param.error=bad_credentials" />
        <logout logout-url="/signout" delete-cookies="JSESSIONID" />
        <intercept-url pattern="/favicon.ico"access="permitAll" />
        <intercept-url pattern="/resources/**" access="permitAll" />
        <intercept-url pattern="/auth/**" access="permitAll" />
        <intercept-url pattern="/signin/**" access="permitAll" />
        <intercept-url pattern="/signup/**" access="permitAll"/>
        <intercept-url pattern="/disconnect/facebook" access="permitAll" />
        <intercept-url pattern="/**" access="isAuthenticated()"/>
        <remember-me />
        <!-- Spring Social Security authentication filter -->
        <custom-filter ref="socialAuthenticationFilter" before="PRE_AUTH_FILTER" />
      </http>

这个怎么运作...

在此实现中,用户可以通过使用数据库中的某些凭据或使用社交网站 ID 和密码来登录应用程序。 SocialAuthenticationProvider 类连同 SocialAuthenticationFilter 处理 身份验证 到社交网站,UserDetailsS​​ervice 管理数据库身份验证。这两个类在 security.xml 文件中进行配置。

以下是实施的工作流程。访问 URL:http://localhost:8080/spring-social-showcase-sec-xml/signin。您将被定向到以下网页:

读书笔记《spring-security-3-x-cookbook》Spring Security 与 Spring Social 访问 Twitter

也可以看看

  • Spring Security with Spring Social 访问 Facebook 秘诀

  • Spring Security with Spring Social 访问 Twitter 秘诀

  • Spring Security with OAuth 秘诀

使用 OAuth 的 Spring 安全性


OAuth 身份验证已被许多应用程序广泛使用。 OAuth 是一种协议,应用程序可以通过该协议以安全的 方式共享数据。例如,考虑一个简单的场景,其中一个照片共享应用程序允许用户上传照片,而第二个应用程序与所有照片存储应用程序(如 Flickr、Dropbox 和类似网站)集成。当第二个应用程序想要访问第一个应用程序以打印上传的照片时,它使用 OAuth 身份验证从用户那里获得访问照片的确认。理想情况下,它确实会在应用程序之间交换一些安全令牌,即消费者的私钥和服务器的公钥应该匹配才能成功授权。

第一个应用程序充当服务器,第二个应用程序充当想要访问某些经过身份验证的数据的消费者。

客户端和服务器应用程序之间交换的一些参数如下:

  • Oauth_consumerKey:我们可以使用应用程序生成OAuth请求

  • Oauth_token:这个 令牌被编码并传递到 URL

  • Oauth_timestamp:这个参数被添加到每个带有nonce的请求中,以防止被服务的请求被再次调用为重放攻击

  • Oauth_version:这个定义了正在使用的OAuth协议的版本

  • Oauth_signaturemethod:该参数用于对请求进行签名验证

  • Oauth_nonce:该参数与时间戳配合使用

  • Size:这个参数定义了文件的大小

  • File:这个参数定义文件名

让我们开发一个示例客户端-服务器应用程序来演示 Spring Security 的 OAuth:

  • 服务器应用程序:让我们考虑一个电影故事应用程序。该应用程序接受来自用户的故事。用户可以将他们的故事上传到应用程序。此应用程序的行为类似于服务提供者。用户写了一些恐怖故事并将其提交给电影制作公司。

  • 客户端应用程序:考虑另一个接受从服务器应用程序上传的故事的电影制作公司应用程序。电影制作公司必须从电影故事应用程序获得授权才能下载故事。

准备好

执行 以下任务以将 Spring Security 与 OAuth 集成:

  • 使用 ConfirmAccessControllerStoryController 类创建服务器应用程序

  • 创建客户端应用程序以访问服务器数据

  • pom.xml 文件中添加 spring-security-oauth 依赖

怎么做...

以下是将 spring-securityspring-oauth 集成的步骤:

  1. 为故事创建 CreateStoryController 类。

    @Controller
    public class CreateStoryController {
      @RequestMapping(value="/stories", method=RequestMethod.GET)
      @ResponseBody
      public String loadStory() {
        StringBuilder horrorStory = new StringBuilder();
        horrorStory.append("Story Name -- Conjuring: Author").append(getAuthorName()).append(" Story:She and that girl and occasionally another girl went out several times a week, and the rest of the time Connie spent around the house—it was summer vacation—getting in her mother's way and thinking, dreaming about the boys she met. But all the boys fell back and dissolved into a single face that was not even a face but an idea, a feeling, mixed up with the urgent insistent pounding of the music and the humid night air of July. Connie's mother kept dragging her back to the daylight by finding things for her to do or saying suddenly, 'What's this about the Pettinger girl?");
        return horrorStory.toString();
      }
      private String getAuthorName() {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String author;
        if (principal instanceof UserDetails) {
          author = ((UserDetails)principal).getUsername();
        } else {
          author = principal.toString();
        }
        return author;
      }
    }
  2. 创建 ConfirmAccessController 类。

    @Controller
    public class ConfirmAccessController {
      private ClientAuthenticationCache clientauthenticationCache = new DefaultClientAuthenticationCache();
      private ClientDetailsService clientDetailsService;
      public ClientAuthenticationCache getAuthenticationCache() {
        return clientauthenticationCache;
      }
      @RequestMapping(value="/oauth/confirm_access")
      public ModelAndView accessConfirmation(HttpServletRequest request, HttpServletResponse response) {
        ClientAuthenticationToken clientAuthtoken = getAuthenticationCache().getAuthentication(request, response);
        if (clientAuthtoken == null) {
          throw new IllegalStateException("We did not recive any client authentication to authorize");
        }
        ClientDetails client = getClientDetailsService().loadClientByClientId(clientAuthtoken.getClientId());
        TreeMap<String, Object> model = new TreeMap<String, Object>();
        model.put("auth_request", clientAuthtoken);
        model.put("client", client);
        return new ModelAndView("access_confirmation", model);
      }
      public ClientDetailsService getClientDetailsService() {
        return clientDetailsService;
      }
      @Autowired
      public void setClientDetailsService(
          ClientDetailsService clientDetailsService) {
        this.clientDetailsService = clientDetailsService;
      }
    }
  3. 使用 OAuth 配置 Spring 安全性。

    <!-- Root Context: defines shared resources visible to all other web components -->
      <http auto-config='true'>
      <intercept-url pattern="/**" access="ROLE_EDITOR" />
      </http>
      <authentication-manager>
        <authentication-provider>
          <user-service>
            <user name="anju" password="anju123" authorities="ROLE_EDITOR" />
          </user-service>
        </authentication-provider>
      </authentication-manager>
      <!--apply the oauth client context -->
      <oauth:client token-services-ref="oauth2TokenServices" />
      <beans:bean id="oauth2TokenServices" class="org.springframework.security.oauth2.consumer.token.InMemoryOAuth2ClientTokenServices" />
      <oauth:resource id="story" type="authorization_code" clientId="movie" accessTokenUri="http://localhost:8080/story/oauth/authorize" userAuthorizationUri="http://localhost:8080/story/oauth/user/authorize" />
        <beans:bean id="storyService" class="org.springsource.oauth.StoryServiceImpl">
        <beans:property name="storyURL" value="http://localhost:8080/story/stories"></beans:property>
        <beans:property name="storyRestTemplate">
          <beans:bean class="org.springframework.security.oauth2.consumer.OAuth2RestTemplate">
          <beans:constructor-arg ref="story"/>
          </beans:bean>
        </beans:property>
        <beans:property name="tokenServices" ref="oauth2TokenServices"></beans:property>
      </beans:bean>
    </beans:beans>
    

这个怎么运作...

必须先访问 movieCompanyapp 网站。 movieCompanyapp 依次从 storyapp 站点获取故事。所以我们必须在同一个端口部署 两个应用程序。

我们为 movieCompanyapp 创建了两个用户(raghu/raghu123 ="literal">anju/anju123 for storyapp)。当用户点击Get stories from storyapp链接时,用户会被要求再次登录。这次用户必须输入他们的凭据,然后他们才能阅读故事。

访问网址:http://localhost:8080/movieCompanyapp/spring_security_login;jsessionid=3b654cf3917d105caa7c273283b5

读书笔记《spring-security-3-x-cookbook》Spring Security 与 Spring Social 访问 Twitter
读书笔记《spring-security-3-x-cookbook》Spring Security 与 Spring Social 访问 Twitter

将被要求授权,以便将故事展示给公司。这发生在 storyapp 应用程序中。

读书笔记《spring-security-3-x-cookbook》Spring Security 与 Spring Social 访问 Twitter

授权后,故事将在 movieCompanyapp 中可用。

读书笔记《spring-security-3-x-cookbook》Spring Security 与 Spring Social 访问 Twitter

也可以看看

  • Spring Security with Spring Social 访问 Facebook 秘诀

  • Spring Security with Spring Social 访问 Twitter 秘诀

  • 具有多个身份验证提供程序的 Spring Security 配方