CAS Server集成QQ登錄、新浪微博登錄源碼及配置文件

轉載自素文宅博客:https://blog.yoodb.com/yoodb/article/detail/1446
CAS Server集成QQ第三方登錄,CAS Server集成新浪微博第三方登錄以及CAS Server集成微信網頁登錄源碼和配置基本類似,本文着重介紹一下如何通過CAS Server(cas-server3.5.2)實現qq第三方登錄,並分享一下實現代碼和具體配置文件內容,雖然包含新浪微博登錄但是未經測試,有什麼疑問可留言。

首先簡單介紹一下CAS Server,它是一套基於Java實現的服務,該服務以一個Java Web Application單獨部署在與servlet2.3兼容的Web服務器上。由於CAS Client與CAS Server之間的交互採用Https協議,因此部署CAS Server的服務器還需要支持SSL協議。當SSL配置成功過後,像普通Web應用一樣將CAS Server部署在服務器上就能正常運行了,也可通過手動修改配置取消對SSL協議的支持。

cas-server集成QQ第三方登錄
1、打開cas-server工程中cas-server-support-oauth子項目,創建QQApi20.java類文件名稱並繼承DefaultApi20.java類,具體代碼如下:
package org.jasig.cas.support.oauth.qq;
import org.jasig.cas.support.oauth.OAuthConstants;
import org.scribe.builder.api.DefaultApi20;
import org.scribe.model.OAuthConfig;
import org.scribe.utils.OAuthEncoder;
public class QQApi20 extends DefaultApi20 {
private static String serverUrl = “”;

@Override
public String getAccessTokenEndpoint() {
    return serverUrl + "/" + OAuthConstants.QQ_ACCESS_TOKEN_URL + "?grant_type=authorization_code";
}

@Override
public String getAuthorizationUrl(final OAuthConfig config) {
    return String.format(serverUrl + "/" + OAuthConstants.AUTHORIZE_URL
    + "?client_id=%s&redirect_uri=%s&response_type=code", config.getApiKey(),
    OAuthEncoder.encode(config.getCallback()));
}

public static void setServerUrl(final String url) {
    serverUrl = url;
}

}

2、創建QQProvider.java類文件名稱並繼承BaseOAuth20Provider.java類,具體代碼如下:
package org.jasig.cas.support.oauth.qq;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.jasig.cas.support.oauth.OAuthConstants;
import org.jasig.cas.support.oauth.entity.UserInfo;
import org.jasig.cas.support.oauth.profile.QQWrapperProfile;
import org.scribe.builder.ServiceBuilder;
import org.scribe.model.Token;
import org.scribe.up.profile.JsonHelper;
import org.scribe.up.profile.UserProfile;
import org.scribe.up.provider.BaseOAuth20Provider;
import org.scribe.up.provider.BaseOAuthProvider;
import org.springframework.orm.jpa.JpaTemplate;

import com.fasterxml.jackson.databind.JsonNode;

/**
* This class is the OAuth provider to authenticate user in CAS server wrapping OAuth protocol.
*
* @author Jerome Leleu
* @since 3.5.0
*/
public final class QQProvider extends BaseOAuth20Provider {

private String serverUrl;

private JpaTemplate jpaTemplate;

@Override
protected void internalInit() {
    QQApi20.setServerUrl(this.serverUrl);
    this.service = new ServiceBuilder().provider(QQApi20.class).apiKey(this.key).apiSecret(this.secret)
        .callback(this.callbackUrl).build();
}

@Override
protected String getProfileUrl() {
    return this.serverUrl + "/" + OAuthConstants.QQ_PROFILE_URL;
}

@Override
protected UserProfile extractUserProfile(final String body) {

    final QQWrapperProfile userProfile = new QQWrapperProfile();
    String str = body.replace("callback( ", "").replace(" );", "");
    JsonNode json = JsonHelper.getFirstNode(str);
    userProfile.setId(JsonHelper.get(json, QQWrapperProfile.ID));
    userProfile.addAttribute(QQWrapperProfile.CLIENTID, JsonHelper.get(json, QQWrapperProfile.CLIENTID));
    return userProfile;
}

private static String getRandomStr(){
    SimpleDateFormat formatter = new SimpleDateFormat ("MMddHHmmss");
    Date curDate = new Date(System.currentTimeMillis());//獲取當前時間
    String str = formatter.format(curDate);
    String cur = str.substring(0,2);
    String cur2 = str.substring(2,4);
    String temp = (Integer.parseInt(cur)+Integer.parseInt(cur2))+""+str.substring(4);
    int cur_id = Integer.parseInt(temp.substring(0,4))+Integer.parseInt(temp.substring(4));
    String randomstr ="y" + cur_id + (int)(Math.random()*10000);
    return randomstr;
}

@SuppressWarnings({ "deprecation", "rawtypes" })
@Override
protected UserProfile getUserProfile(final Token accessToken) {
    final String body = sendRequestForData(accessToken, getProfileUrl());
    if (body == null) {
        return null;
    }
    final UserProfile profile = extractUserProfile(body);
    addAccessTokenToProfile(profile, accessToken);
    String url = "https://graph.qq.com/user/get_user_info?access_token="+accessToken.getToken()+"&oauth_consumer_key="+this.key+"&openid="+profile.getId();
    String response = getHttp(url);
    JsonNode json = JsonHelper.getFirstNode(response);
    String ret = json.get("ret").asText();
    if(ret != null && ret.equals("0")){
        List list = jpaTemplate.find("from UserInfo where openid='"+profile.getId()+"'");
        UserInfo userInfo = null;
        if(list == null || list.isEmpty()){
            userInfo = new UserInfo();
            String nickName = json.get("nickname").asText();
            nickName = nickName.replaceAll("[^0-9a-zA-Z\\u4e00-\\u9fa5]", "");
            userInfo.setNickName(nickName);
            userInfo.setAvatar(json.get("figureurl_qq_1").asText());
            userInfo.setGender(json.get("gender").asText());
            userInfo.setOpenId(profile.getId());
            userInfo.setClientId((String)profile.getAttributes().get(QQWrapperProfile.CLIENTID));
            userInfo.setUserName(getRandomStr());
            userInfo.setCompleted(0);
            if(userInfo.getNickName() == null || userInfo.getNickName().equals("")){
                userInfo.setNickName(userInfo.getUserName());
            }
            userInfo.setCreateTime(new Date());
            jpaTemplate.persist(userInfo);
        }else{
            userInfo = (UserInfo) list.get(0);
            userInfo.setUpdateTime(new Date());
            jpaTemplate.merge(userInfo);
        }
        profile.setId(userInfo.getUserName());
        profile.addAttribute("userId",userInfo.getUserId());
        profile.addAttribute("userName",userInfo.getUserName());
        profile.addAttribute("nickName",userInfo.getNickName());
        profile.addAttribute("avatar",userInfo.getAvatar());
        profile.addAttribute("gender",userInfo.getGender());
        profile.addAttribute("openId",userInfo.getOpenId());
        profile.addAttribute("clientId",userInfo.getClientId());
        profile.addAttribute("completed",userInfo.getCompleted());
    }
    return profile;
}

public static String getHttp(String url) {
    String responseMsg = "";
    HttpClient httpClient = new HttpClient();
    GetMethod getMethod = new GetMethod(url);
    getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,new DefaultHttpMethodRetryHandler());
    try {
        httpClient.executeMethod(getMethod);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        InputStream in = getMethod.getResponseBodyAsStream();
        int len = 0;
        byte[] buf = new byte[1024];
        while((len=in.read(buf))!=-1){
            out.write(buf, 0, len);
        }
        responseMsg = out.toString("UTF-8");
    } catch (HttpException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //釋放連接
        getMethod.releaseConnection();
    }
    return responseMsg;
}

public void setServerUrl(final String serverUrl) {
    this.serverUrl = serverUrl;
}

@Override
protected BaseOAuthProvider newProvider() {
    final QQProvider newProvider = new QQProvider();
    newProvider.setServerUrl(this.serverUrl);
    return newProvider;
}

public JpaTemplate getJpaTemplate() {
    return jpaTemplate;
}

public void setJpaTemplate(JpaTemplate jpaTemplate) {
    this.jpaTemplate = jpaTemplate;
}

}

3、在cas-server-webapp子項目中,打開applicationContext.xml文件,添加對應的oauth的clients信息並把clients增加到對應的org.pac4j.core.client.Clients中,具體配置內容下:

<bean id="sinaWeibo" class="org.jasig.cas.support.oauth.sina.SinaWeiboProvider">
        <property name="key" value="xxxxxxxxxxxxxxxx" />  
        <property name="secret" value="xxxxxxxxxxxxxxxxxxxxxxxxxxxx" />
        <property name="serverUrl" value="https://api.weibo.com/oauth2"/>
        <property name="callbackUrl" value="http://api.yoodb.com" />  <!-- oauth10login -->
</bean>
<bean id="qq" class="org.jasig.cas.support.oauth.qq.QQProvider"><!--新浪微博bean配置,跳過-->
    <property name="jpaTemplate" ref="jpaTemplate"/>
    <property name="key" value="xxxxxxxxxxxx" />  
    <property name="secret" value="xxxxxxxxxxxxxxxxxxxx" />
    <property name="serverUrl" value="https://graph.qq.com/oauth2.0"/>
    <property name="callbackUrl" value="http://api.yoodb.com" />  <!-- oauth10login -->
</bean>

4、在cas-server-webapp子項目中,打開deployerConfigContext.xml文件,增加bean配置,具體配置內容下:

<bean class="org.jasig.cas.support.oauth.OAuthConfiguration" id="oAuthConfiguration">
<property name="loginUrl" value="http://api.yoodb.com"/>
<property name="providers">         
            <list>           
                <ref bean="sinaWeibo" /><!--新浪微博配置,跳過-->
                <ref bean="qq" />                       
            </list>       
        </property>
</bean>

5、添加以下鏈接到登錄頁面casLoginView.jsp(ClientNameUrl這個屬性是被OAuthConfiguration自動創建),也就是你自定義的Client類名加上Url。如我創建的類爲QQProvider則對應的link名爲QQProviderUrl,具體代碼如下:

<div class="row btn-row third-part">
                        <p class="third_login"><span>第三方帳號登錄</span></p>
                        <a href="${QQProviderUrl}" class="qq"></a>
                        <a href="javascript:alert('目前只有QQ登錄可以使用!');" class="sina"></a> 
<%--                        <a href="${SinaWeiboProviderUrl}" class="sina"></a>  --%>
                        <a href="javascript:alert('目前只有QQ登錄可以使用!');" class="baidu"></a>
                        <a href="javascript:alert('目前只有QQ登錄可以使用!');" class="wechat"></a>
                     </div>

cas-server集成新浪微博第三方登錄
1、打開cas-server工程中cas-server-support-oauth子項目,創建SinaWeiboApi20.java類文件名稱並繼承DefaultApi20.java類,具體代碼如下:
package org.jasig.cas.support.oauth.sina;

import org.jasig.cas.support.oauth.OAuthConstants;
import org.scribe.builder.api.DefaultApi20;
import org.scribe.model.OAuthConfig;
import org.scribe.utils.OAuthEncoder;

public class SinaWeiboApi20 extends DefaultApi20 {
private static String serverUrl = “”;

@Override
public String getAccessTokenEndpoint() {
    return serverUrl + "/" + OAuthConstants.SINA_ACCESS_TOKEN_URL + "?";
}

@Override
public String getAuthorizationUrl(final OAuthConfig config) {
    return String.format(serverUrl + "/" + OAuthConstants.AUTHORIZE_URL
            + "?client_id=%s&redirect_uri=%s&response_type=code", config.getApiKey(),
            OAuthEncoder.encode(config.getCallback()));
}

public static void setServerUrl(final String url) {
    serverUrl = url;
}

}

2、創建SinaWeiboProvider.java類文件名稱並繼承BaseOAuth20Provider.java類,具體代碼如下:
package org.jasig.cas.support.oauth.sina;

import java.util.Iterator;

import org.jasig.cas.support.oauth.OAuthConstants;
import org.jasig.cas.support.oauth.profile.CasWrapperProfile;
import org.scribe.builder.ServiceBuilder;
import org.scribe.up.profile.JsonHelper;
import org.scribe.up.profile.UserProfile;
import org.scribe.up.provider.BaseOAuth20Provider;
import org.scribe.up.provider.BaseOAuthProvider;

import com.fasterxml.jackson.databind.JsonNode;

/**
* This class is the OAuth provider to authenticate user in CAS server wrapping OAuth protocol.
*
* @author Jerome Leleu
* @since 3.5.0
*/
public final class SinaWeiboProvider extends BaseOAuth20Provider {

private String serverUrl;

@Override
protected void internalInit() {
    SinaWeiboApi20.setServerUrl(this.serverUrl);
    this.service = new ServiceBuilder().provider(SinaWeiboApi20.class).apiKey(this.key).apiSecret(this.secret)
        .callback(this.callbackUrl).build();
}

@Override
protected String getProfileUrl() {
    return this.serverUrl + "/" + OAuthConstants.SINA_PROFILE_URL;
}

@Override
protected UserProfile extractUserProfile(final String body) {
    final CasWrapperProfile userProfile = new CasWrapperProfile();
    JsonNode json = JsonHelper.getFirstNode(body);
    if (json != null) {
        userProfile.setId(JsonHelper.get(json, CasWrapperProfile.ID));
        json = json.get(CasWrapperProfile.ATTRIBUTES);
        if (json != null) {
            final Iterator<JsonNode> nodes = json.iterator();
            while (nodes.hasNext()) {
                json = nodes.next();
                final String attribute = json.fieldNames().next();
                userProfile.addAttribute(attribute, JsonHelper.get(json, attribute));
            }
        }
    }
    return userProfile;
}

public void setServerUrl(final String serverUrl) {
    this.serverUrl = serverUrl;
}

@Override
protected BaseOAuthProvider newProvider() {
    final SinaWeiboProvider newProvider = new SinaWeiboProvider();
    newProvider.setServerUrl(this.serverUrl);
    return newProvider;
}

}
cas-server集成新浪微博登錄和在cas-server集成qq登錄類似,參考一下(本文中已經增加新浪微博配置及步驟但未經過測試),此處省略。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章