Java微信公众平台开发之OAuth2.0网页授权

来源:互联网 发布:数控车床编程实例 编辑:程序博客网 时间:2024/06/05 06:13

根据官方文档,在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头,最新的要在域名空间的根目录放一个叫MP_verify_dTx4Hrh6cZDHUEgH.txt才能验证通过。(可能是最近加进去的,之前测试的没发现)


两种scope授权方式:

1、以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
2、以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息


具体文档详见https://mp.weixin.qq.com/wiki/4/9ac2e7b1f1d22e9e57260f6553822520.html


1.用户同意授权,获取code

我这边是snsapi_userinfo发起的网页授权

我是直接在菜单测试的,或者你直接推送给测试用户都行,反正能打开这个链接就行了

redirect_uri必须用urlEncode处理下

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. ViewButton btn12 = new ViewButton();    
  2.         btn12.setName("授权测试");      
  3.         btn12.setType("view");  
  4.         String redirect_uri = "http://域名/项目名/oauth";  
  5.         String redirect_uris = null;  
  6.         try {  
  7.             redirect_uris = URLEncoder.encode(redirect_uri,"utf-8");  
  8.             logger.info(redirect_uris);    
  9.         } catch (UnsupportedEncodingException e) {  
  10.             e.printStackTrace();  
  11.         }  
  12.         String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri="+redirect_uris+"&response_type=code&scope=snsapi_userinfo&state=123#wechat_redirect";  
  13.         logger.info(url);         
  14.         btn12.setUrl(url);  

用户打开之后,如果同意的话,可以用request.getParameter("code")直接获取到code。code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. @Controller  
  2. @RequestMapping("/oauth")  
  3. public class OAuthController {  
  4.       
  5.     private static final Logger logger = Logger.getLogger(OAuthController.class);  
  6.       
  7.     @Autowired  
  8.     private OAuthService oAuthService;  
  9.       
  10.     @RequestMapping(method = { RequestMethod.GET })  
  11.     public String processGet(HttpServletRequest request, HttpServletResponse response, String url) throws Exception{      
  12.         //request.setCharacterEncoding("gb2312");  
  13.         //response.setCharacterEncoding("gb2312");    
  14.         //用户同意授权后可以获得code  
  15.         String code = request.getParameter("code");  
  16.         logger.info("用户同意授权后的code: "+code);   
  17.         //用户同意授权  
  18.         if(!"authdeny".equals(code)){  
  19.             //获取网页授权access_token  
  20.             Oauth2Token oauth2Token = oAuthService.getOauth2AccessToken(WechatConfig.APP_ID, WechatConfig.APP_SECRET, code);  
  21.             //获取用户信息  
  22.             SNSUserInfo suser = oAuthService.getSNSUserInfo(oauth2Token.getAccessToken(), oauth2Token.getOpenId());  
  23.             if(suser!=null){              
  24.                 //执行保存绑定                  
  25.                 String openid = suser.getOpenid();  
  26.                 logger.info("绑定的openid="+openid);                 
  27.                 request.setAttribute("suser", suser);  
  28.             }  
  29.         }  
  30.         //  
  31.         return "test/test"//转发到指定的url  
  32.     }  
  33. }  

2.通过code换取网页授权access_token

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public class Oauth2Token {  
  2.     //网页授权接口调用凭证  
  3.     private  String accessToken;  
  4.     //凭证有效时长  
  5.     private int expiresIn;  
  6.     //用于刷新凭证  
  7.     private String refreshToken;  
  8.     //用户标识  
  9.     private String openId;  
  10.     //用户授权作用域  
  11.     private String scope;  
  12.       
  13.     public String getAccessToken() {  
  14.         return accessToken;  
  15.     }  
  16.     public void setAccessToken(String accessToken) {  
  17.         this.accessToken = accessToken;  
  18.     }  
  19.     public int getExpiresIn() {  
  20.         return expiresIn;  
  21.     }  
  22.     public void setExpiresIn(int expiresIn) {  
  23.         this.expiresIn = expiresIn;  
  24.     }  
  25.     public String getRefreshToken() {  
  26.         return refreshToken;  
  27.     }  
  28.     public void setRefreshToken(String refreshToken) {  
  29.         this.refreshToken = refreshToken;  
  30.     }  
  31.     public String getOpenId() {  
  32.         return openId;  
  33.     }  
  34.     public void setOpenId(String openId) {  
  35.         this.openId = openId;  
  36.     }  
  37.     public String getScope() {  
  38.         return scope;  
  39.     }  
  40.     public void setScope(String scope) {  
  41.         this.scope = scope;  
  42.     }  
  43. }  
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 获取网页授权凭证 
  3.  * @param appId 公众账号的唯一标识 
  4.  * @param appSecret 公众账号的密钥 
  5.  * @param code 
  6.  * @return 
  7.  */  
  8. public Oauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {  
  9.     Oauth2Token ot = null;  
  10.     String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";  
  11.     requestUrl = requestUrl.replace("APPID", appId).replace("SECRET", appSecret).replace("CODE", code);       
  12.     logger.info("requestUrl"+requestUrl);     
  13.     //获取网页授权凭证  
  14.     JSONObject jsonObject = HttpRequestUtil.httpRequestJSONObject(requestUrl, HttpRequestUtil.GET_METHOD, null);  
  15.     if(null != jsonObject){  
  16.         try {  
  17.             ot = new Oauth2Token();  
  18.             ot.setAccessToken(jsonObject.getString("access_token"));  
  19.             ot.setExpiresIn(jsonObject.getInt("expires_in"));  
  20.             ot.setRefreshToken(jsonObject.getString("refresh_token"));  
  21.             ot.setOpenId(jsonObject.getString("openid"));  
  22.             ot.setScope(jsonObject.getString("scope"));  
  23.         } catch (Exception e) {  
  24.             int errorCode = jsonObject.getInt("errcode");  
  25.             String errorMsg = jsonObject.getString("errmsg");  
  26.             logger.info("获取网页授权凭证失败,错误码:"+errorCode+",错误提示:"+errorMsg);  
  27.         }  
  28.     }  
  29.     return ot;  
  30. }  
3.刷新access_token(如果需要)

由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。

获取第二步的refresh_token后,请求以下链接获取access_token:  
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN ,需要的话自己替换下URL就好了

4.拉取用户信息

如果是scope是snsapi_base,拉取用户的openid; 如果scope是 snsapi_userinfo,可以拉取到全部信息

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public class SNSUserInfo {  
  2.     //用户标识  
  3.     private String openid;  
  4.     //用户昵称  
  5.     private String nickname;  
  6.     //性别(1是男性,2是女性,0是未知)  
  7.     private String sex;  
  8.     //国家  
  9.     private String country;  
  10.     //省份  
  11.     private String province;  
  12.     //城市  
  13.     private String city;  
  14.     //用户头像链接  
  15.     private String headimgurl;  
  16.     //用户特权信息  
  17.     private List<String> privilege;  
  18.     //只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段   
  19.     private String unionid;  
  20.       
  21.     public String getOpenid() {  
  22.         return openid;  
  23.     }  
  24.     public void setOpenid(String openid) {  
  25.         this.openid = openid;  
  26.     }  
  27.     public String getNickname() {  
  28.         return nickname;  
  29.     }  
  30.     public void setNickname(String nickname) {  
  31.         this.nickname = nickname;  
  32.     }  
  33.     public String getSex() {  
  34.         return sex;  
  35.     }  
  36.     public void setSex(String sex) {  
  37.         this.sex = sex;  
  38.     }  
  39.     public String getCountry() {  
  40.         return country;  
  41.     }  
  42.     public void setCountry(String country) {  
  43.         this.country = country;  
  44.     }  
  45.     public String getProvince() {  
  46.         return province;  
  47.     }  
  48.     public void setProvince(String province) {  
  49.         this.province = province;  
  50.     }  
  51.     public String getCity() {  
  52.         return city;  
  53.     }  
  54.     public void setCity(String city) {  
  55.         this.city = city;  
  56.     }  
  57.     public String getHeadimgurl() {  
  58.         return headimgurl;  
  59.     }  
  60.     public void setHeadimgurl(String headimgurl) {  
  61.         this.headimgurl = headimgurl;  
  62.     }  
  63.     public List<String> getPrivilege() {  
  64.         return privilege;  
  65.     }  
  66.     public void setPrivilege(List<String> privilege) {  
  67.         this.privilege = privilege;  
  68.     }  
  69.     public String getUnionid() {  
  70.         return unionid;  
  71.     }  
  72.     public void setUnionid(String unionid) {  
  73.         this.unionid = unionid;  
  74.     }  
  75. }  

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 通过网页授权获取用户信息 
  3.  * @param oauth2Token 
  4.  * @return 
  5.  */  
  6. public SNSUserInfo getSNSUserInfo(String accessToken, String openId) {  
  7.     SNSUserInfo suser = null;  
  8.     String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";  
  9.     requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);       
  10.     //通过网页授权获取用户信息  
  11.     JSONObject jsonObjet = HttpRequestUtil.httpRequestJSONObject(requestUrl, HttpRequestUtil.GET_METHOD, null);  
  12.     if(null != jsonObjet){  
  13.         try {  
  14.             suser = new Gson().fromJson(jsonObjet.toString(), SNSUserInfo.class);  
  15.         } catch (JsonSyntaxException e) {  
  16.             logger.info("transfer exception");  
  17.             throw e;                  
  18.         }   
  19.     }  
  20.     return suser;  
  21. }  

获取到SNSUserInfo之后,可以选择与数据库的用户绑定。

如果想解绑网站账号的话,可以学中信的公众号一样加个安全设置再解绑,相应的把openid从关联的用户表删除,可以加个绑定和解绑的时间日志。


问:如果PC端网站想绑定微信等第三方,把第一步的那个url作为场景ID生成一个临时的带参二维码,扫描之后输入网站的用户名密码就可以与公众号绑定了。试问是这样做的吗?

1 0
原创粉丝点击