使用Spring Boot实现社交网络登录

概述

这是关于在使用Spring Boot构建web应用程序时实现SNS登录功能的备注。

环境

Java 8(抱歉)
Spring Boot 2.1.0.RELEASE

Java 8(对不起)
Spring Boot 2.1.0.RELEASE

春天社交已经终止

以下是对上述链接的中文释义:

https://projects.spring.io/spring-social/
– Spring Social 是一个用于构建和扩展社交应用程序的开源框架。

https://spring.io/blog/2018/07/03/spring-social-end-of-life-announcement
– Spring Social 宣布停止更新。

使用库。

应用目标社交媒体

    • Facebook

 

    Google

执行

①POM (产品运营经理)

<!-- OAuth2 authentication-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

配置。


// ログインに関わる部分のみ抜粋しています。
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @NonNull
    SaveAndGenerateUserDetails saveAndGenerateUserDetails

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // SNSログイン
                .oauth2Login()
                    .loginPage("/login")
                    .userInfoEndpoint()
                    // OAuth認証時に実行するServiceクラス
                    .userService(new OAuth2UserService(saveAndGenerateUserDetails))
                    // OpenId認証時に実行するServiceクラス
                    .oidcUserService(new OidcUserDetailsService(saveAndGenerateUserDetails))
                .and()
                    // 必要があればSuccessHandlerを実装
                    .successHandler(new MyAuthenticationSuccessHandler())
                    // 必要があればSuccessHandlerを実装。今回はデフォルト。
                    .failureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"))
            .and()
                // ID PASSログインを共存できる
                .formLogin()
                    .loginPage("/login")
                        .usernameParameter("username")
                        .passwordParameter("password")
                        .permitAll()
                    .successHandler(new FormLoginSuccessHandler())
                    .failureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"))
            .and()
                .logout()
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                    .logoutSuccessUrl("/")
                    .invalidateHttpSession(true)
                    .deleteCookies("JSESSIONID")
                    .permitAll()
            .and()
                .exceptionHandling();


}

③应用程序配置文件 application.yml

spring:
  security:
    oauth2:
      client:
        registration:
          facebook:
            client-id: 【client-id】
            client-secret: 【client-secret】
            scope:
              - email
              - public_profile
            redirect-uri: 【アプリケーションのURL】/login/oauth2/code/{registrationId}
          google:
            client-id: 【client-id】
            client-secret: 【client-secret】
            scope:
              - email
              - profile
              - openid
            redirect-uri: 【アプリケーションのURL】/login/oauth2/code/{registrationId}
        provider:
          facebook:
            authorizationUri: https://www.facebook.com/v3.3/dialog/oauth
            tokenUri: https://graph.facebook.com/v3.3/oauth/access_token
            userInfoUri: https://graph.facebook.com/v3.3/me

④观点

<!-- 各SNSログインのエンドポイントを設定したリンクをつくります。 
     エンドポイントは固定値で下記の通りです。 -->
<!-- 〜もろもろ省略〜 -->
<a href="/oauth2/authorization/facebook">Facebookログイン</a>
<a href="/oauth2/authorization/google">Googleログイン</a>
<!-- 〜もろもろ省略〜 -->

服务
⑤-1 OAuth类(在SecurityConfig的.userService()中进行设置)

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OAuth2UserService
        extends DefaultOAuth2UserService {

    @NonNull
    SaveAndGenerateUserDetails saveAndGenerateUserDetails

    @Override
    @Transactional(readOnly = false)
    public OAuth2User loadUser(OAuth2UserRequest userRequest)
            throws OAuth2AuthenticationException {

        // 実装クラスの紹介は省略します。
        // 概略:
        // registrationIdで分岐して、取得したい情報を取り出す処理をSNSごとにクラスを作成。
        // 取得した情報を元にUser情報をDBに保存
        // 取得した情報を元に認証情報(UserDetails)を返却します。
        // 本クラスの戻り値の型は認証方法によって異なりますが、processメソッドの戻り値の型は、MyUserDetails
        // なのでここで認証方法の差を吸収します。
        return saveAndGenerateUserDetails.process(userRequest,
                super.loadUser(userRequest));
    }
}

⑤-2 在 OpenId 認證後進行的處理(設定在 SecurityConfig 的 .oidcUserService() 中)

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OidcUserDetailsService
        extends OidcUserService {

    @NonNull
    SaveAndGenerateUserDetails saveAndGenerateUserDetails;

    @Override
    @Transactional(readOnly = false)
    public OidcUser loadUser(OidcUserRequest userRequest)
            throws OAuth2AuthenticationException {

        // ⑤-1と同様
        return saveAndGenerateUserDetails.process(userRequest,
                super.loadUser(userRequest));
    }
}

我的用户详细信息类 (Wǒ de

@SuppressWarnings("serial")
@Data
public class MyUserDetails implements UserDetails, OAuth2User, OidcUser {

    // @Overrideすべきメソッドはよしなに。
    // SNSログインに必要な部分のみ抜粋しています。

    private Map<String, Object> attributes;

    // コンストラクタ
    public MyUserDetails(MyUser user, Map<String, Object> attr) {
        // OAuth、OpenIdの情報のみ記載しています。
        this.attributes = attr;
    }
}

印象

Paraphrasing the sentences in natural Chinese:

・比我想象中需要自行准备的类少得多了
・尽管被库方面处理得挺好,但它还是个黑匣子,也挺有帮助的
・只要实现oauth和openid中的一种,就可以轻松地进行横向扩展

请提供参考链接

    • https://www.callicoder.com/spring-boot-security-oauth2-social-login-part-1/

 

    • https://www.callicoder.com/spring-boot-security-oauth2-social-login-part-2/

 

    • https://www.baeldung.com/spring-security-5-oauth2-login

 

    https://www.codeflow.site/ja/article/spring-security-5-oauth2-login
bannerAds