サードパーティ上陸

41014 ワード

文書ディレクトリ
  • OAuthプロトコル概要
  • 微信自撮りデータ共有例
  • OAuthプロトコルの役割と実行フロー
  • ロール
  • フロー
  • ライセンスモード
  • 認証コードパターン
  • Spring Social基本原理
  • Spring Social基本インタフェース
  • 第三者登録:QQ
  • APIインタフェース
  • QQUserInfo
  • QQ
  • QQImpl
  • ServiceProviderインタフェース
  • QQServiceProvider
  • QQOAuth2Template
  • ApiAdapterインタフェース
  • QQAdapter
  • ConnectionFactory
  • QQConnectionFactory
  • UsersConnectionRepository
  • 表構造
  • 構成
  • OAuthプロトコルの概要
  • OAuthプロトコルはどのような問題を解決しますか
  • OAuthプロトコルの主要な役割
  • OAuthプロトコル実行フロー
  • 微信自撮りデータ共有の例
    微信自撮りで得た写真は、第三者が写真を美化したいと応用している.どのようにしてサードパーティアプリケーションに微信のユーザー権限を取得させることができますか?
  • 難点
  • 1、テンセントは第三者アプリケーションが直接ユーザーの私有データ情報にアクセスすることを許可しない
    2、ユーザーが第三者アプリケーションのユーザーデータの読み取りに同意した場合、どのような「同意」法がありますか.
    アカウントのパスワードを第三者に直接提供することはできないでしょう.
    3、サードパーティアプリケーションがユーザーの微信でのユーザー名パスワードを取得した場合、以下の問題が発生する
    1、サードパーティアプリケーションはユーザーが微信のすべてのデータにアクセスできる
    2、ユーザーはパスワードを変更してこそ、権限を取り戻すことができる
    3、パスワードの漏洩の可能性が大幅に高まる
    この例では、OAuthプロトコルは、ライセンスの問題をこのように解決します.
    微信のアカウントパスワードを第三者に適用するのではなく、このTokenに権限情報、期限切れ時間があり、このTokenでユーザー名パスワードを解読することはできません.
    これにより、セキュリティ、利便性などの問題が同時に解決されます.
    以上、OAuthプロトコルの基本的な紹介です
    OAuthプロトコルの役割と実行プロセス
    ロール#ロール#
  • サービスプロバイダ:Provider
  • トークンを提供する、例えば、本例の微信(テンセント)
  • リソース所有者:ResourceOwner
  • アクセスが必要なデータリソースの所有者、例えば、この例の微信ユーザ
  • サードパーティアプリケーション:Client
  • 認証サーバ:Authorization Server
  • ユーザのアイデンティティを認証し、トークンを生成する
  • リソースサーバ:ResourceServer
  • 1、ユーザーデータ資源の保存
    2、検証トークン
    一般的な実用開発では、認証サーバとリソースサーバは、1台のマシンであってもよい
    プロセス
    0、微信ユーザーが第三者応用にアクセスする
    1、サードパーティのアプリケーションは微信ユーザーの授権を要求する
    2、微信ユーザーは第三者アプリケーションの授権要求に同意する
    3、第三者アプリケーション認証サーバー申請トークン
    4、タスクサーバは今回のトークン申請が合法であるかどうかを検証する.すなわち、実際のユーザーが許可に同意したかどうかを検証し、トークンを発行する.
    5、サードパーティアプリケーションはトークンを持って資源サーバーに行って資源データを申請する
    6、資源サーバーはトークンが合法かどうかを検証し、合法的に資源を第三者に開放する
    認証モード
    認証コードパターン
    最も完全で、最も包括的で、最も一般的なライセンスモデルです.
    特徴:
    1、ユーザーが授権に同意する動作は、認証サーバーで行われる
    2.サードパーティアプリケーションは認証サーバの認証コードを受信し、トークンを取得する必要があるため、サードパーティアプリケーションには独自のサーバが必要である.サードパーティアプリケーションが通常の静的Webサイトである場合、ライセンスコードモードは使用できません.簡略化モードを使用可能
    Spring Socialの基本原理
    OAuthは本質的に認証プロトコルであり、ユーザが自分のユーザ名のパスワード情報を暴露せずに第三者アプリケーションを認証する問題を解決する
    Spring Socialサードパーティのログインを実現
    現在、多くのサイトやアプリがあります.私たちは微信やQQを使ってログインすることができます.許可さえすれば、アプリやサイトを再登録する必要はありません.
    サードパーティアプリケーションはトークンを用いてユーザ基本情報を取得し,この情報をステップ7に従って処理することで,1回のログインに相当する.
    Spring Socialは6、7の過程をSocialAuthenticationFilterにカプセル化した.
    Spring Social基本インタフェース
  • AbstractOAuth2ServiceProvider:サービスプロバイダ
  • OAuth2OperationsOAuth2Template
  • AbstractOAuth2ApiBinding
  • ConnectionOAuth2Connection
  • ConnectionFactoryOAuth2ConnectionFactory
  • ……

  • 第三者登録:QQ
    QQの第三者登録は、標準的なOAuthプロトコルであり、微信はそうではなく、やや異なり、具体的な後続は述べられる.
    サードパーティのログインは、Webページやアプリで使用できますので、imooc-security-coreプロジェクトに関連コードが書かれています.
    APIインタフェース
    APIインタフェースはテンセントからユーザー情報を取得するために使用される.
    関連クラス:
    では、テンセントからユーザー情報をどのように取得しますか?これはテンセントの文書を見なければなりません.
    テンセント
    ユーザーの基本情報を取得するインタフェースはテンセントのドキュメントです
    QQUserInfo
    取得したQQユーザーの情報をカプセル化する
    package com.imooc.security.core.social.qq.api;
    
    import lombok.Data;
    import lombok.experimental.Accessors;
    
    /**
     *          QQ       
     *
     * @Author sherry
     * @Description
     * @Date Create in 2019-03-27
     * @Modified By:
     */
    @Data
    @Accessors(chain = true)
    public class QQUserInfo {
        private int ret;
        private String openId;
    	  private String msg;
        private String nickname;
        private String figureurl;
        private String figureurl_1;
        private String figureurl_2;
        private String figureurl_qq_1;
        private String figureurl_qq_2;
        private String gender;
        private String is_yellow_vip;
        private String vip;
        private String yellow_vip_level;
        private String level;
        private String is_yellow_year_vip;
    
    }
    
    

    ここの内容はテンセントの文書によって決定されます
    パラメータの説明
    説明
    ret
    リターンコード
    msg
    ret<0の場合、対応するエラーメッセージが表示され、戻りデータはすべてUTF-8で符号化されます.
    nickname
    QQ空間でのユーザーのニックネーム.
    figureurl
    サイズ30×30ピクセルのQQ空間アバターURL.
    figureurl_1
    サイズ50×50ピクセルのQQ空間アバターURL.
    figureurl_2
    サイズは100×100画素のQQ空間の顔のURL.
    figureurl_qq_1
    サイズ40×40ピクセルのQQアイコンURL.
    figureurl_qq_2
    サイズは100×100ピクセルのQQアイコンURL.すべてのユーザーがQQの100 x 100の顔を持っているわけではありませんが、40 x 40ピクセルは必ずあります.
    gender
    性別.取得できない場合はデフォルトで「男」を返します.
    QQ
    インタフェース、QQユーザー情報を取得する
    package com.imooc.security.core.social.qq.api;
    
    import java.io.IOException;
    
    /**
     * @Author sherry
     * @Description
     * @Date Create in 2019-03-27
     * @Modified By:
     */
    
    public interface QQ {
        QQUserInfo getUserInfo();
    }
    
    

    QQImpl
    package com.imooc.security.core.social.qq.api;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.social.oauth2.AbstractOAuth2ApiBinding;
    import org.springframework.social.oauth2.TokenStrategy;
    
    import java.io.IOException;
    
    
    @Slf4j
    public class QQImpl extends AbstractOAuth2ApiBinding implements QQ {
    
    
        private static final String URL_GET_OPENID = "https://graph.qq.com/oauth2.0/me?access_token=%s";
        private static final String URL_GET_USERINFO = "https://graph.qq.com/user/get_user_info?oauth_consumer_key=%s&openid=%s";
    
    
        private String appId;
        private String openId;
    
        private ObjectMapper objectMapper = new ObjectMapper();
    
        public QQImpl(String accessToken, String appId) {
            super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);// access_token  param   
            this.appId = appId;
    
            String url = String.format(URL_GET_OPENID, accessToken);
            String result = getRestTemplate().getForObject(url, String.class);
    
            log.info(result);
    
            this.openId = StringUtils.substringBetween(result, "\"openId\":", "}");
        }
    
        @Override
        public QQUserInfo getUserInfo()  {
            String url = String.format(URL_GET_USERINFO, appId, openId);
            String result = getRestTemplate().getForObject(url, String.class);
            log.info(result);
            return objectMapper.readValue(result, QQUserInfo.class);
        }
    }
    
    /*
    AbstractOAuth2ApiBinding         accessToken  ,            OAuth         ,
               token ,  ,   QQImpl        
     */
    

    ServiceProviderインタフェース
    QQServiceProvider
    package com.imooc.security.core.social.qq.connect;
    
    import com.imooc.security.core.social.qq.api.QQ;
    import com.imooc.security.core.social.qq.api.QQImpl;
    import org.springframework.social.oauth2.AbstractOAuth2ServiceProvider;
    
    public class QQServiceProvider extends AbstractOAuth2ServiceProvider<QQ> {
    
        private String appId;
        private static final String URL_AUTHORIZE="https://graph.qq.com/oauth2.0/authorize";
        private static final String URL_ACCESS_TOKEN="https://graph.qq.com/oauth2.0/token";
    
        /**
         * Create a new {@link OAuth2ServiceProvider}.
         *
         * @param oauth2Operations the OAuth2Operations template for conducting the OAuth 2 flow with the provider.
         */
        public QQServiceProvider(String appId,String appSecret) {
            //            QQOAuth2Template,      、             
            super(new QQOAuth2Template(appId, appSecret, URL_AUTHORIZE, URL_ACCESS_TOKEN));
            this.appId = appId;
        }
    
        @Override
        public QQ getApi(String accessToken) {
            return new QQImpl(accessToken,appId);
        }
    }
    
    
    
    

    QQOAuth2Template
    package com.imooc.security.core.social.qq.connect;
    
    import org.springframework.social.oauth2.*;
    
    /**
     * @Author sherry
     * @Description
     * @Date Create in 2019-03-28
     * @Modified By:
     */
    
    public class QQOAuth2Template extends OAuth2Template {
        public QQOAuth2Template(String appId, String appSecret, String urlAuthorize, String urlAccessToken) {
            super(appId,appSecret,urlAuthorize,urlAccessToken);
        }
    
    }
    
    

    ApiAdapterインタフェース
    テンセントが提供するユーザー情報フォーマットを必要なフォーマットに変換するために使用されます
    QQAdapter
    package com.imooc.security.core.social.qq.connect;
    
    import com.imooc.security.core.social.qq.api.QQ;
    import com.imooc.security.core.social.qq.api.QQUserInfo;
    import org.springframework.social.connect.ApiAdapter;
    import org.springframework.social.connect.ConnectionValues;
    import org.springframework.social.connect.UserProfile;
    
    public class QQAdapter implements ApiAdapter<QQ> {
    
        /**
         *     Api    
         *
         * @param api
         * @return
         */
        @Override
        public boolean test(QQ api) {
            return true;
        }
    
        /**
         * Connection   Api     
         *
         * @param api
         * @param values
         */
        @Override
        public void setConnectionValues(QQ api, ConnectionValues values) {
            QQUserInfo qqUserInfo = api.getUserInfo();
    
            //  Api   QQ       Connection 
            values.setDisplayName(qqUserInfo.getNickname());
            values.setImageUrl(qqUserInfo.getFigureurl_qq_1());
            // QQ      ,  ProfileUrl    
            values.setProfileUrl(null);
            //QQ          
            values.setProviderUserId(qqUserInfo.getOpenId());
        }
    
        @Override
        public UserProfile fetchUserProfile(QQ api) {
            //          
            return null;
        }
    
        /**
         *       (QQ    )
         *
         * @param api
         * @param message
         */
        @Override
        public void updateStatus(QQ api, String message) {
            // do nothing
        }
    }
    

    ConnectionFactory
    QQConnectionFactory
    package com.imooc.security.core.social.qq.connect;
    
    import com.imooc.security.core.social.qq.api.QQ;
    import org.springframework.social.connect.support.OAuth2ConnectionFactory;
    
    public class QQConnectionFactory extends OAuth2ConnectionFactory<QQ> {
    
        public QQConnectionFactory(String providerId, String appId, String appSecret) {
            super(providerId, new QQServiceProvider(appId, appSecret), new QQAdapter());
        }
    }
    

    ProviderId:プロバイダ固有のID、プロファイルからの取り込み
    UsersConnectionRepository
    操作UserConnectionテーブル、テーブル構造は
    テーブル構造
    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);
    

    コンフィギュレーション
    package com.imooc.security.core.social;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.annotation.Order;
    import org.springframework.security.crypto.encrypt.Encryptors;
    import org.springframework.social.config.annotation.EnableSocial;
    import org.springframework.social.config.annotation.SocialConfigurerAdapter;
    import org.springframework.social.connect.ConnectionFactoryLocator;
    import org.springframework.social.connect.UsersConnectionRepository;
    import org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository;
    
    import javax.sql.DataSource;
    
    @Configuration
    @EnableSocial
    @Order(1)
    public class SocialConfigurer extends SocialConfigurerAdapter {
    
        @Autowired
        private DataSource dataSource;
    
        @Override
        public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
            //          ,        Connection   (          ,     ),           (     )
            JdbcUsersConnectionRepository jdbcUsersConnectionRepository =
                    new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator, Encryptors.noOpText());
    
            return jdbcUsersConnectionRepository;
        }
    }