SpringSecurity+SpringSocial 实现QQ登入(一)

1.原理

SpringSecurity+SpringSocial 实现QQ登入(一)_第1张图片

Social实现QQ登入符合Oauth2协议,基本步骤如上图,步骤1-5都是固定的(Social已经封装好),步骤6获取的用户信息各不相同需要自定义,步骤7就是我们的登入原理了。

接着通过SocialAuthenticationFilter加入过滤器链中
SpringSecurity+SpringSocial 实现QQ登入(一)_第2张图片

下面是我们需要实现的:SpringSecurity+SpringSocial 实现QQ登入(一)_第3张图片

2. 代码开发

api编写

public interface QQ {
    QQUserInfo getUserInfo() ;
}

public class QQImpl extends AbstractOAuth2ApiBinding implements QQ{

    protected final Log logger = LogFactory.getLog(getClass());

    private String openid;

    private String appId;

    private ObjectMapper objectMapper = new ObjectMapper();

    //获取用户openid的url
    private static final String URL_GET_OPENID = "https://graph.qq.com/oauth2.0/me?access_token=%s";

    //获取用户信息的url (注:accessToken不用传,系统会自动加上去)
    private static  final String URL_GET_USERINFO ="https://graph.qq.com/user/get_user_info?oauth_consumer_key=%s";


    public QQImpl(String accessToken,String appId) {
        super(accessToken,TokenStrategy.ACCESS_TOKEN_PARAMETER);
        this.appId = appId;
        //通过Access Token,得到对应用户身份的OpenID。
        //https://graph.qq.com/oauth2.0/me?access_token=F679F117539B5042872183269AF866E5
        //callback( {"client_id":"101726424","openid":"6F204B99FF2E96686342B71B7FFC384A"} );
        String url_openid = String.format(URL_GET_OPENID,accessToken);
        String tar = getRestTemplate().getForObject(url_openid, String.class);

        logger.info("通过Access Token,得到对应用户身份的OpenID,返回数据 【"+ tar +"】");
        this.openid = StringUtils.substringBetween(tar,"\"openid\":\"","\"}");
    }

    /**
     * 获取用户信息
     * @return
     */
    @Override
    public QQUserInfo getUserInfo()  {

        String url_user = String.format(URL_GET_USERINFO,this.appId);

        String tar = getRestTemplate().getForObject(url_user, String.class);

        logger.info("获取用户信息,返回数据 【"+ tar +"】");

        QQUserInfo qqUserInfo = null;
        try {
            qqUserInfo = objectMapper.readValue(tar, QQUserInfo.class);
        } catch (IOException e) {
            logger.info("获取用户信息失败 【"+ e.getMessage() +"】");
        }

        return qqUserInfo;
    }


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 figureurl_qq;

	private String figureurl_type;


	/**
	 * 	性别。 如果获取不到则默认返回”男”
	 */
	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;

	private String constellation;

	public String getConstellation() {
		return constellation;
	}

	public void setConstellation(String constellation) {
		this.constellation = constellation;
	}

	public String getRet() {
		return ret;
	}
	public void setRet(String ret) {
		this.ret = ret;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
	public String getOpenId() {
		return openId;
	}
	public void setOpenId(String openId) {
		this.openId = openId;
	}
	public String getIs_lost() {
		return is_lost;
	}
	public void setIs_lost(String is_lost) {
		this.is_lost = is_lost;
	}
	public String getProvince() {
		return province;
	}
	public void setProvince(String province) {
		this.province = province;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	public String getYear() {
		return year;
	}
	public void setYear(String year) {
		this.year = year;
	}
	public String getNickname() {
		return nickname;
	}
	public void setNickname(String nickname) {
		this.nickname = nickname;
	}
	public String getFigureurl() {
		return figureurl;
	}
	public void setFigureurl(String figureurl) {
		this.figureurl = figureurl;
	}
	public String getFigureurl_1() {
		return figureurl_1;
	}
	public void setFigureurl_1(String figureurl_1) {
		this.figureurl_1 = figureurl_1;
	}
	public String getFigureurl_2() {
		return figureurl_2;
	}
	public void setFigureurl_2(String figureurl_2) {
		this.figureurl_2 = figureurl_2;
	}
	public String getFigureurl_qq_1() {
		return figureurl_qq_1;
	}
	public void setFigureurl_qq_1(String figureurl_qq_1) {
		this.figureurl_qq_1 = figureurl_qq_1;
	}
	public String getFigureurl_qq_2() {
		return figureurl_qq_2;
	}
	public void setFigureurl_qq_2(String figureurl_qq_2) {
		this.figureurl_qq_2 = figureurl_qq_2;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public String getIs_yellow_vip() {
		return is_yellow_vip;
	}
	public void setIs_yellow_vip(String is_yellow_vip) {
		this.is_yellow_vip = is_yellow_vip;
	}
	public String getVip() {
		return vip;
	}
	public void setVip(String vip) {
		this.vip = vip;
	}
	public String getYellow_vip_level() {
		return yellow_vip_level;
	}
	public void setYellow_vip_level(String yellow_vip_level) {
		this.yellow_vip_level = yellow_vip_level;
	}
	public String getLevel() {
		return level;
	}
	public void setLevel(String level) {
		this.level = level;
	}
	public String getIs_yellow_year_vip() {
		return is_yellow_year_vip;
	}
	public void setIs_yellow_year_vip(String is_yellow_year_vip) {
		this.is_yellow_year_vip = is_yellow_year_vip;
	}

	public String getFigureurl_qq() {
		return figureurl_qq;
	}

	public void setFigureurl_qq(String figureurl_qq) {
		this.figureurl_qq = figureurl_qq;
	}

	public String getFigureurl_type() {
		return figureurl_type;
	}

	public void setFigureurl_type(String figureurl_type) {
		this.figureurl_type = figureurl_type;
	}
}

ApiAdapter 编写

public class QQApiAdapter implements ApiAdapter {

    @Override
    public boolean test(QQ api) {
        return true;
    }

    @Override
    public void setConnectionValues(QQ api, ConnectionValues values) {
        //将qq用户数据转成通用的connection数据
        QQUserInfo userInfo = api.getUserInfo();
        values.setDisplayName(userInfo.getNickname());
        values.setImageUrl(userInfo.getFigureurl_qq_1());
        values.setProfileUrl(null);
        values.setProviderUserId(userInfo.getOpenId());
    }

    @Override
    public UserProfile fetchUserProfile(QQ api) {
        return null;
    }

    @Override
    public void updateStatus(QQ api, String message) {

    }
}

ServiceProvider

public class QQServiceProvider extends AbstractOAuth2ServiceProvider {

    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) {
        //super(oauth2Operations);
        super(new OAuth2Template(appId, appSecret, URL_AUTHORIZE,URL_ACCESS_TOKEN));
    }

    @Override
    public QQ getApi(String accessToken) {
        return new QQImpl(accessToken,appId);
    }
}

ConnectionFactory

public class QQConnectionFactory extends OAuth2ConnectionFactory {
    /**
     * Create a {@link OAuth2ConnectionFactory}.
     *
     * @param providerId      the provider id e.g. "facebook"
     * @param serviceProvider the ServiceProvider model for conducting the authorization flow and obtaining a native service API instance.
     * @param apiAdapter      the ApiAdapter for mapping the provider-specific service API model to the uniform {@link Connection} interface.
     */
    public QQConnectionFactory(String providerId,String appId,String appSecret) {
        super(providerId,new QQServiceProvider(appId,appSecret),new QQApiAdapter() );
    }
}

基本的类已经编写完成,接下来就是把各个类通过配置串联起来。

你可能感兴趣的:(springSecutiry)