发放给用户一个令牌,用户经过令牌来访问数据.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(); }