梁方勇 陳桂強
(華中師范大學,湖北 武漢 430079)
隨著信息技術和移動互聯網的快速發展,尤其是微信、企業微信、微信公眾平臺的廣泛應用,各高校均在大力推進數字校園建設,并依托企業微信、微信公眾號等平臺將各業務系統集成到平臺中,為廣大師生提供便捷的移動互聯服務。在PC 時代,各高校一般通過單點登錄(SSO)實現統一身份認證,需要輸入統一的用戶名和密碼,根據權限進入各自的業務系統。在移動互聯時代,人們已經習慣利用移動互聯平臺快速獲取信息、進行移動辦公。一方面,如果使用傳統技術登錄OA 等移動端業務系統,需要掃碼二維碼或憑用戶名、密碼登錄,操作體驗不夠便捷。另一方面,各單位業務系統已經實現了PC 端的單點登錄,擁有較好的基礎,需要通過技術手段遷移到移動端,實現移動端的身份認證。
在企業微信平臺下,通過系統設計和技術研發,將企業微信的OAuth 身份認證功能與單點登錄(SSO)中的CAS 認證有機融合,實現無感登錄,即無須輸入用戶名和密碼即可登錄企業微信平臺,并根據用戶權限訪問不同的業務系統,有效減輕使用人員記憶密碼的負擔,提升用戶使用體驗,提高用戶身份認證的安全性和便利性,已成為當前高校數字校園移動互聯系統設計中需要解決的重要問題。基于這樣一種設想,該文通過具體案例,研究探索該功能的實現路徑,該系統設計方案同時適用于微信公眾平臺、微信小程序與SSO集成融合,也可為其他高校的數字校園建設提供一定的參考借鑒。
各單位的信息化建設是一個循序漸進的過程,在建設中根據各種需要構建了相應的信息系統,并形成了各自獨立的用戶認證體系。如果不引入單一用戶登錄的解決方案,工作人員需要記憶各類系統的用戶名和密碼,用戶容易混淆或者忘記登錄信息[1],嚴重影響工作效率。
單點登錄(Single Sign On),簡稱為SSO,為實現用戶統一身份認證的重要組成部分[2],是比較流行的企業業務整合的解決方案之一。通過應用SSO 技術可實現登錄一次訪問所有應用系統。
SSO 一般將開源軟件CAS 作為基礎平臺,包括CAS Client 和CAS Server 兩個部分。CAS Client 負責處理對客戶端受保護資源的訪問請求,需要登錄時,重定向到CAS Server;CAS Server 主要負責對用戶的認證工作。CAS 認證過程如圖1 所示。

圖1 CAS 認證過程
圖1 說明了CAS 的認證過程[3],共分為6 步。第一步,用戶通過客戶端瀏覽器請求訪問應用;第二步,CAS Client將該請求重定向到CAS Server;第三步,用戶輸入信息,CAS Server 進行認證;第四步,認證成功后CAS Server 會產生一個隨機Service Ticket;第五步,驗證票據。CAS Server 驗證Service Ticket 的合法性;第六步,返回用戶信息。CAS Server 驗證票據通過后,返回用戶認證結果信息。
企業微信平臺實現無感登錄的本質是對訪問者身份信息進行認證[4]。根據微信開發者文檔,獲取用戶身份信息實現單點登錄可分為5 步。第一步獲取授權標識code。可以通過前端網頁加載一個url,調用企業微信接口獲取授權標識code;第二步獲取accessToken。它是企業微信或微信公眾號的唯一接口調用憑據,可以使用corpId 和Secret 調用接口來獲取accessToken,調用各類接口時都必須使用accessToken;第三步,獲取用戶ID(userid)。通過code 和accessToken 調用接口獲取用戶信息userid;第四步通過userid 獲取用戶信息。通過userid 和accessToken 調用接口獲取用戶信息userinfo;第五步是與單點登錄系統進行集成融合。整個流程如圖2 所示。

圖2 數字校園下基于單點登錄的企業微信無感登錄系統的流程圖
數字校園下基于單點登錄的企業微信無感登錄系統的整體架構如圖3 所示。首先,用戶登錄企業微信或微信公眾平臺。其次,通過后臺調用接口取得userid,并對該userid進行身份驗證。最后,驗證通過后集成單點登錄系統,即可根據權限進入不同業務系統。

圖3 系統整體架構圖
該文以基于單點登錄的企業微信無感登錄系統為例,根據上述系統架構及流程設計,各模塊的核心Java 代碼如下。
3.2.1 企業微信平臺登錄模塊代碼
企業微信平臺登錄實質上就是鏈接到一個Web 頁面地址,例如本系統中為http://hrzm.ccnu.edu.cn/login.jsp,通過在登錄login.jsp 頁面中添加JavaScript 代碼,JavaScript 程序就會開始檢測,如果客戶端為微信平臺,則跳轉到企業微信接口域,此接口域內含重定向的服務器地址url。前端login.jsp 頁面核心代碼如下:
<SCRIPT LANGUAGE="JavaScript">
function init(){
var weixin=is_weixin();//判斷是否微信平臺
if(weixin){
window.location="https://open.weixin.qq.com/connect/oauth2/authorize?appid=corpid&redirect_uri=http%3A%2F%2fhrzm.ccnu.edu.cn%2FloginWxOauth2Action.do&response_type=code&scope=snsapi_base&state=#wechat_redirect。";//進 入移動端微信登錄}
else{
window.location="/login.do";//進入PC 端單點登錄
}}
init();
</SCRIPT>
跳轉成功后即轉發服務器地址url,同時地址中會自動帶上授權標識code,在后臺可以通過返回的url 獲得授權標識code,獲得授權標識code 的Java 代碼如下:
String code = request.getParameter(“code”);
此模塊的流程如圖4 所示。

圖4 登錄模塊獲取授權標識code 流程圖
3.2.2 獲取accessToken 模塊代碼
根據企業號corpID和Secret調用企業微信接口來獲取accessToken。核心Java 代碼[5]如下:
/** * 獲取AccessToken
*/
public static AccessToken getAccessToken(){
AccessToken token = new AccessToken();
try{
String url="https://gyapi.weixin.gg.com/cgi-bin/gettoken?corpid="+ID+"&corpsecret ="+SECRET ;//ID 和SECRET 為static final 變量,可在微信公眾平臺開發者中心頁面獲得
JSONObject jsObj = doGetStr(url);//解析url
if(jsObj!=null){
token.setAccessToken(jsObj.getString("access_token"));//設置access_token
token.setExpiresIn(jsObj.getInt("expires_in"));// 設 置access_token 的有效期
return token;}
}catch (Exception e) {token =null;}
return null;
}
3.2.3 獲取用戶ID 模塊代碼
根據獲取的code 和accessToken 調用企業微信接口獲取用戶信息userid。核心Java 代碼如下:
/** * 根據AccessToken 和code 獲取用戶id
*/
public static String getUserID(String access_token, String code){
String UserId = "";
String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token="+access_token+"&code="+code;
JSONObject jsObj= doGetStr(url);//解析url if(jsObj!=null){
UserId = jsObj.getString("UserId");}return UserId;
}
取得UserID 后,存儲到request 中,并轉發單點登錄模塊。
request.setAttribute("UserId", UserId);
request.getRequestDispatcher("/sso.do").forward(request,response);
3.2.4 根據用戶ID 獲取用戶信息
通過獲取的userid 和accessToken 調用接口獲取用戶信息userinfo,可以得到用戶的mobile、e-mail、name 等信息。核心Java 代碼如下:
/** * 根據AccessToken 和userid 獲取用戶信息
*/
public static JSONObject getUserID(String access_token, String userid) {
String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token="+access_token+"&userid="+userid;
JSONObject UserInfo = doGetStr(url);
if(UserInfo !=null){return UserInfo;}
}
3.2.5 集成單點登錄系統代碼
從request 中取得userid 后,會進入正常的表單登錄認證的AuthenticationHandler 中,需要在執行正常的認證邏輯之前插入企業微信認證邏輯。CAS 服務器則保存用戶憑證Principal,通過驗證用戶憑證即可訪問各業務系統。核心Java代碼如下:
String UserId=request.getAttribute("UserId");
if(!UserId.notEqual(null)&&!UserId.notEqual(""){
credential.setUsername(UserId);
Return createHandlerResult(credential,this.principleFactory.createPrincipal(credential.getUsername()),null);
}
//驗證用戶憑證代碼
AttributePrincipal principal = (AttributePrincipal)request.getUserPrincipal();
String userName = principal.getName();//通過用戶憑證獲取username
最后通過取得的userName 得到用戶權限,進入不同的業務系統,如此即實現了基于單點登錄的企業微信無感登錄系統。整個登錄過程在用戶層面是感受不到登錄過程的,把便利留給了用戶,極大地提升了用戶體驗。
系統采用B/S 架構,運行環境選擇安裝jdk1.7.0_72,Web服務器采用Apache Tomcat7.0.100,數據庫為Oracle 10,操作系統為Microsoft Sever,開發語言為Java、Jsp、HTML、JavaScript。以及需要下載安裝第三方庫,包括struts 庫、requests 庫、json 庫和單點登錄SSO 依賴包cas-server-3.5.1+cas-client-3.2.1 等。
企業微信平臺使用OAuth2.0 標準實施安全驗證。OAuth2.0 是一個關于授權(authorization)的開放網絡標準,OAuth2.0 中使用的授權碼模式(authorization code)是功能最完整、流程最嚴密的授權模式,也是最安全的一種模式。這使集成單點登錄系統后的整個系統的安全性也得到了很好的保障。
該文提出了Java 語言環境中數字校園下基于單點登錄的企業微信無感登錄系統,通過將企業微信的OAuth 身份認證與單點登錄(SSO)中的CAS 認證相融合,較好地解決了企業微信平臺下登錄多個業務系統時無須輸入用戶名和密碼的問題,有效減輕了使用人員記憶密碼的負擔,對提升用戶使用體驗有較大意義,同時應用OAuth2.0安全機制也保障了系統的安全性。實例驗證標明,該無感登錄系統設計方案亦適用于微信公眾號等平臺下與業務系統的集成,具有較強的拓展性。