Spring Social總結(一)

OAuth協議

含義

發放給用戶一個令牌,用戶經過令牌來訪問數據.spring

流程

image.png

受權模式

  • 受權碼模式
  • 簡化模式
  • 密碼模式
  • 客戶端模式

受權碼模式

image.png

SpringSocial實現第三方登錄
基本原理

當用戶使用受權碼模式拿到令牌以後,能夠在服務器上獲取用戶的基本信息,而後根據用戶信息構建Authentication,並放入SecurityContext,此時對於SpringSecurity已經登錄成功.
image.png
SpringSocial將整個流程封裝成SocialAuthenticationFilter添加到過濾器鏈上
image.png數據庫

具體實現

image.png

  • ServiceProvider(AbstractOAuth2ServiceProvider):服務提供商的抽象,針對每一個具體的服務提供商(好比qq,微信等)提供的接口的實現,並提供抽象類AbstractOAuth2ServiceProvider,咱們實現這個抽象類api

    • OAuth2Operations(OAuth2Template):OAuth協議相關的操做,OAuth2Template完成OAuth協議的執行流程
    • api(AbstractOAuth2ApiBinding):實現獲取用戶信息
  • Connection(OAuth2Connection):封裝以前獲取到的用戶信息,實際實現類爲OAuth2Connection
  • ConnectionFactory(OAuth2ConnectionFactory):負責建立OAuth2Connectionspringboot

    • ServiceProvider:封裝了前面全部的流程,經過調用ServiceProvider走前面全部的流程,走通以後經過獲取到的用戶數據建立OAuth2Connection對象
    • ApiAdapter:不一樣的服務提供商具備不一樣的用戶數據結構,ApiAdapter主要負責將不一樣的數據獵狗轉換成Connection標準的數據結構
  • UserConnection:在數據庫中,將咱們業務的用戶於服務提供商的用戶創建對應關係
  • UserConnectionRepository(JdbcUserConnectionRepository):負責操做UserConnection的對應關係,JdbcUserConnectionRepository負責針對UserConnection表中的數據作增刪改查的操做

QQ登陸

封裝QQ登陸返回的用戶數據服務器

@Data
public class QQUserInfo {
    /** 返回碼 */
    private String ret;
    /** 若是ret<0,會有相應的錯誤信息提示,返回數據所有用UTF-8編碼。 */
    private String msg;
    /**  */
    private String openId;
    /** 不知道什麼東西,文檔上沒寫,可是實際api返回裏有。 */
    private String is_lost;
    /** 省(直轄市) */
    private String province;
    /** 市(直轄市區) */
    private String city;
    /** 出生年月 */
    private String year;
    /** 用戶在QQ空間的暱稱。 */
    private String nickname;
    /** 大小爲30×30像素的QQ空間頭像URL。 */
    private String figureurl;
    /** 大小爲50×50像素的QQ空間頭像URL。 */
    private String figureurl_1;
    /** 大小爲100×100像素的QQ空間頭像URL。 */
    private String figureurl_2;
    /** 大小爲40×40像素的QQ頭像URL。 */
    private String figureurl_qq_1;
    /** 大小爲100×100像素的QQ頭像URL。須要注意,不是全部的用戶都擁有QQ的100×100的頭像,但40×40像素則是必定會有。 */
    private String figureurl_qq_2;
    /** 性別。 若是獲取不到則默認返回」男」 */
    private String gender;
    /** 標識用戶是否爲黃鑽用戶(0:不是;1:是)。 */
    private String is_yellow_vip;
    /** 標識用戶是否爲黃鑽用戶(0:不是;1:是) */
    private String vip;
    /** 黃鑽等級 */
    private String yellow_vip_level;
    /** 黃鑽等級 */
    private String level;
    /** 標識是否爲年費黃鑽用戶(0:不是; 1:是) */
    private String is_yellow_year_vip;
}

創建獲取用戶信息的接口微信

public interface QQ {
    QQUserInfo getUserInfo();
}

創建QQ接口的實現類,並繼承AbstractOAuth2ApiBinding抽象類,數據結構

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;
    priate String openId;
    public QQImpl(String accessToken, String appId) {
        super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);
        this.appId = appId;
        String url = String.format(URL_GET_OPENID, accessToken);
        String result = getRestTemplate().getForObject(url, String.class);
        System.out.println(result);
        this.openId = String.valueOf(JSONUtil.parseObj(result).get("openid"));
    }
    /**
     * 獲取用戶信息
     *
     * @return
     */
    @Override
    public QQUserInfo getUserInfo() {
        String url = String.format(URL_GET_USERINFO, appId, openId);
        String result = getRestTemplate().getForObject(url, String.class);
        System.out.println(result);
        QQUserInfo userInfo = null;
        try {
            userInfo = JSONUtil.toBean(result, QQUserInfo.class);
            userInfo.setOpenId(openId);
            return userInfo;
        } catch (Exception e) {
            throw new RuntimeException("獲取用戶信息失敗", e);
        }
    }
}

實現ServiceProviderapp

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";
    public QQServiceProvider(String appId, String appSecret) {
        super(new OAuth2Template(appId, appSecret, URL_AUTHORIZE, URL_ACCESS_TOKEN));
    }
    @Override
    public QQ getApi(String accessToken) {
        return new QQImpl(accessToken, appId);
    }
}

實現ApiAdapteride

public class QQAdapter implements ApiAdapter<QQ> {
    //發出請求判斷請求是否是通的,true爲是通的,不發出請求
    @Override
    public boolean test(QQ qq) {
        return true;
    }
    //適配onnection數據和api數據
    @Override
    public void setConnectionValues(QQ qq, ConnectionValues values) {
        QQUserInfo userInfo = qq.getUserInfo();
        values.setDisplayName(userInfo.getNickname());
        values.setImageUrl(userInfo.getFigureurl_qq_1());
        values.setProfileUrl(null);
        values.setProviderUserId(userInfo.getOpenId());
    }
    @Override
    public UserProfile fetchUserProfile(QQ qq) {
        return null;
    }
    @Override
    public void updateStatus(QQ qq, String s) {
    }
}

實現ConnectionFactoryfetch

public class QQConnectionFactory extends OAuth2ConnectionFactory<QQ> {
    public QQConnectionFactory(String providerId, String appId, String appSecret) {
        super(providerId, new QQServiceProvider(appId, appSecret), new QQAdapter());
    }
}

qq登陸的各項配置

public class QQProperties extends SocialProperties {
    private String providerId = "qq";
    public String getProviderId() {
        return providerId;
    }
    public void setProviderId(String providerId) {
        this.providerId = providerId;
    }
}

注:springboot2.0在org.springframework.boot.autoconfigure裏沒有social相關的配置簡化類。直接將SocialAutoConfigurerAdapter、SocialProperties和SocialWebAutoConfiguration這三個類拷貝到項目裏
將QQProperties添加到總體的SecurityProperties中

public class SocialProperties {
    private QQProperties qq = new QQProperties();
}
相關文章
相關標籤/搜索