發放給用戶一個令牌,用戶經過令牌來訪問數據.spring
當用戶使用受權碼模式拿到令牌以後,能夠在服務器上獲取用戶的基本信息,而後根據用戶信息構建Authentication,並放入SecurityContext,此時對於SpringSecurity已經登錄成功.
SpringSocial將整個流程封裝成SocialAuthenticationFilter添加到過濾器鏈上數據庫
ServiceProvider(AbstractOAuth2ServiceProvider):服務提供商的抽象,針對每一個具體的服務提供商(好比qq,微信等)提供的接口的實現,並提供抽象類AbstractOAuth2ServiceProvider,咱們實現這個抽象類api
ConnectionFactory(OAuth2ConnectionFactory):負責建立OAuth2Connectionspringboot
封裝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(); }