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();
}
相关文章
相关标签/搜索