微信公衆號快速開發(四)微信網頁受權

引入受權

OAuth2概念引入

OAuth2.0是OAuth協議的延續版本,但不向前兼容OAuth 2.0(即徹底廢止了OAuth1.0)。 OAuth 2.0關注客戶端開發者的簡易性。要麼經過組織在資源擁有者和HTTP服務商之間的被批准的交互動做表明用戶,要麼容許第三方應用表明用戶得到訪問的權限。html

以上來自百度百科,即OAuth由Resourse Owner(資源全部者),Client(客戶端),以及Provider(服務提供商)組成,Provider包括Authorization Server(認證服務器)和Resource Server(資源服務器)兩部分。java

微信的網頁受權是基於OAuth2.0協議。好比當咱們的公衆號中要修改用戶的基本信息時,公衆號就要先獲取微信中的用戶數據;又或者用戶修改圖片時須要訪問手機的相冊。若是按傳統的方式,用戶登陸公衆號以後,第三方的公衆號就能夠隨意從微信端獲取用戶信息,或是手機的所有數據,這就形成了密碼泄露的隱患,當你不想使用該公衆號又擔憂數據外泄,只能修改密碼。web

微信網頁受權流程

OAuth協議的出現正是爲了解決上述這些問題。他將用戶名密碼受權方式改成經過令牌受權,第三方應用請求訪問資源,資源全部者(用戶)贊成受權後,再次訪問服務提供商(微信官方)去向認證服務器申請令牌(Token),認證服務器贊成後發放令牌(Token),而後第三方應用再拿這個令牌(Token)去向資源服務器(微信官方)申請想要的資源,資源服務器驗證經過後開放這個應用所需的資源。json

具體而言,網頁受權流程分爲四步:api

  1. 引導用戶進入受權頁面贊成受權,獲取code
  2. 經過code換取網頁受權access_token(與基礎支持中的access_token不一樣)
  3. 若是須要,開發者能夠刷新網頁受權access_token,避免過時
  4. 經過網頁受權access_token和openid獲取用戶基本信息(支持UnionID機制)

具體介紹參見公衆號開發文檔->微信網頁受權安全

開發準備

1、微信web開發者工具服務器

便於在客戶端調式,下載地址:微信web開發者工具微信

2、配置網頁帳號app

微信測試公衆平臺->體驗接口權限->網頁服務->網頁帳號->網頁受權獲取用戶基本信息->修改ide

這裏暫時仍是使用內網穿透的域名,若須要開發微信支付功能,需使用真實域名。

3、配置靜態頁面

根據開發文檔的返回json,擬作一個頁面,用於顯示用戶的信息

靜態資源位置:templates/person.html,該頁面用於顯示用戶的詳細信息

開發步驟

用戶贊成受權,獲取code

1、URL

根據文檔,引導網頁受權的URL的格式爲:open.weixin.qq.com/connect/oau…

注意:

  1. 微信會對受權連接作正則強匹配校驗,若是連接的參數順序不對,受權頁面將沒法正常訪問;
  2. 回調redirect_uri,應當使用https連接來確保受權code的安全;
  3. 網頁受權做用域爲snsapi_userinfo,後續即可以經過access_tokenopenid拉取用戶信息;
  4. 若是用戶贊成受權,頁面將跳轉至 redirect_uri/?code=CODE&state=STATE;
  5. 參數說明,以下圖:

2、添加轉發頁面的控制器

由於本項目暫時使用的時thymeleaf模板,沒法直接訪問項目中的靜態資源,所以須要配置重定向的Controller。(爲了跳轉方便,後面頁面與URL保持不重名)

  • IndexController:
@Controller
@RequestMapping("/api/v1/wechat1")
public class IndexController {

    // 用於thymeleaf環境下,跳轉到字符串相應的html頁面
    @RequestMapping("/{path}")
    public String webPath(@PathVariable String path) {
        return path;
    }

    @RequestMapping("/index")
    public void index(String code, Model model, HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 顯式受權,得到code
        if (code != null) {
            JSONObject accessTokenJson = WeChatUtil.getWebAccessToken(code);
            WXPayUtil.getLogger().info("獲取網頁受權的AccessToken憑據: "+accessTokenJson.toJSONString());
            String openid = accessTokenJson.getString(("openid"));
            request.getSession().setAttribute("openid", openid);
            WXPayUtil.getLogger().info("index openid={}"+openid);
            // 重定向到預下單頁面
            response.sendRedirect("user"); // 回調的訪問地址
        } else {
            StringBuffer url = RequestUtil.getRequestURL(request);
            WXPayUtil.getLogger().info("index 請求路徑:{}"+url);
            String path = WeChatUtil.WEB_REDIRECT_URL.replace("APPID", WeChatConstants.APP_ID).replace("REDIRECT_URI", url).replace("SCOPE", "snsapi_userinfo");
            WXPayUtil.getLogger().info("index 重定向:{}"+path);
            // 重定向到受權獲取code的頁面
            response.sendRedirect(path);
        }
    }
}    
複製代碼

3、啓動項目,訪問:chety.mynatapp.cc/api/v1/wech…

4、根據URL的格式,替換相關參數。訪問: 微信受權頁面

open.weixin.qq.com/connect/oau…

5、點擊【贊成】後,頁面將自動跳轉到【/person.html】中

在重定向的URL中,能夠看到code和state(這裏沒有設置,因此爲空)

code說明 : code做爲換取access_token的票據,每次用戶受權帶上的code將不同,code只能使用一次,5分鐘未被使用自動過時

經過code換取網頁受權access_token

1、URL

獲取code後,請求如下連接獲取access_token: api.weixin.qq.com/sns/oauth2/…

因爲公衆號的secret和獲取到的access_token安全級別都很是高,必須只保存在服務器,不容許傳給客戶端。後續刷新access_token、經過access_token獲取用戶信息等步驟,也必須從服務器發起。

2、添加獲取access_token的方法

  • WeChatUtil
//獲取網頁受權accessToken的接口
public static final String GET_WEB_ACCESSTOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";


/** * 經過code換取網頁受權access_token * @param code * @return */
public static JSONObject getWebAccessToken(String code){
    String result = HttpUtil.get(GET_WEB_ACCESSTOKEN_URL.replace("APPID", WeChatConstants.APP_ID).replace("SECRET", WeChatConstants.APPSECRET).replace("CODE", code));
    return JSONObject.parseObject(result);
}
複製代碼

返回說明

刷新access_token(若是須要)

因爲access_token擁有較短的有效期,當access_token超時後,可使用refresh_token進行刷新,refresh_token有效期爲30天,當refresh_token失效以後,須要用戶從新受權。

1、URL

獲取第二步的refresh_token後,請求如下連接獲取access_token: api.weixin.qq.com/sns/oauth2/…

grant_type填寫爲refresh_token

2、添加工具類方法

// 獲取網頁受權accessToken的接口
public static final String GET_WEB_ACCESSTOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";

/** * 刷新access_token * @param refresh_token * @return */
public static JSONObject refreshWebAccessToken(String refresh_token){
    String result = HttpUtil.get(GET_WEB_ACCESSTOKEN_URL.replace("APPID", WeChatConstants.APP_ID).replace("REFRESH_TOKEN", refresh_token));
    return JSONObject.parseObject(result);
}
複製代碼

拉取用戶信息(需scope爲 snsapi_userinfo)

1、URL

http:GET(請使用https協議) api.weixin.qq.com/sns/userinf…

2、添加工具類方法

/** * 獲取用戶信息 * @param accessToken * @param openId * @return */
public static JSONObject getUserInfo(String accessToken,String openId){
    String result = HttpUtil.get(GET_USERINFO_URL.replace("ACCESS_TOKEN", accessToken).replace("OPENID",openId));
    return JSONObject.parseObject(result);
}
複製代碼

3、添加跳轉用戶信息的接口

/** * 網頁受權獲取用戶信息 * @param code * @return */
@RequestMapping("/user")
public String person(String code,ModelMap map){
    if(code!=null) {
        //經過code來換取access_token
        JSONObject result = WeChatUtil.getWebAccessToken(code);
        //經過access_token和openid拉取用戶信息
        JSONObject userInfo = WeChatUtil.getUserInfo(result.getString("access_token"), result.getString("openid"));
        WXPayUtil.getLogger().info("用戶信息爲:{}"+ JSON.toJSONString(userInfo));
        //獲取json對象中的鍵值對集合
        Set<Map.Entry<String, Object>> entries = userInfo.entrySet();
        for (Map.Entry<String, Object> entry : entries) {          
            map.addAttribute(entry.getKey(),entry.getValue());
        }
    }
    return "person";
}
複製代碼

這裏包含用戶信息的鍵名直接用了微信返回的默認值,person頁面也使用該默認名。

4、再次訪問:

open.weixin.qq.com/connect/oau…

能夠看到,已經獲取了微信中返回的信息

附:檢驗受權憑證(access_token)是否有效

http:GET(請使用https協議) api.weixin.qq.com/sns/auth?ac…

相關文章
相關標籤/搜索