根据官方文档,在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是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处理下
- ViewButton btn12 = new ViewButton();
- btn12.setName("授权测试");
- btn12.setType("view");
- String redirect_uri = "http://域名/项目名/oauth";
- String redirect_uris = null;
- try {
- redirect_uris = URLEncoder.encode(redirect_uri,"utf-8");
- logger.info(redirect_uris);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- 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";
- logger.info(url);
- btn12.setUrl(url);
用户打开之后,如果同意的话,可以用request.getParameter("code")直接获取到code。code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期
- @Controller
- @RequestMapping("/oauth")
- public class OAuthController {
-
- private static final Logger logger = Logger.getLogger(OAuthController.class);
-
- @Autowired
- private OAuthService oAuthService;
-
- @RequestMapping(method = { RequestMethod.GET })
- public String processGet(HttpServletRequest request, HttpServletResponse response, String url) throws Exception{
-
-
-
- String code = request.getParameter("code");
- logger.info("用户同意授权后的code: "+code);
-
- if(!"authdeny".equals(code)){
-
- Oauth2Token oauth2Token = oAuthService.getOauth2AccessToken(WechatConfig.APP_ID, WechatConfig.APP_SECRET, code);
-
- SNSUserInfo suser = oAuthService.getSNSUserInfo(oauth2Token.getAccessToken(), oauth2Token.getOpenId());
- if(suser!=null){
-
- String openid = suser.getOpenid();
- logger.info("绑定的openid="+openid);
- request.setAttribute("suser", suser);
- }
- }
-
- return "test/test";
- }
- }
2.通过code换取网页授权access_token
- public class Oauth2Token {
-
- private String accessToken;
-
- private int expiresIn;
-
- private String refreshToken;
-
- private String openId;
-
- private String scope;
-
- public String getAccessToken() {
- return accessToken;
- }
- public void setAccessToken(String accessToken) {
- this.accessToken = accessToken;
- }
- public int getExpiresIn() {
- return expiresIn;
- }
- public void setExpiresIn(int expiresIn) {
- this.expiresIn = expiresIn;
- }
- public String getRefreshToken() {
- return refreshToken;
- }
- public void setRefreshToken(String refreshToken) {
- this.refreshToken = refreshToken;
- }
- public String getOpenId() {
- return openId;
- }
- public void setOpenId(String openId) {
- this.openId = openId;
- }
- public String getScope() {
- return scope;
- }
- public void setScope(String scope) {
- this.scope = scope;
- }
- }
-
-
-
-
-
-
-
- public Oauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {
- Oauth2Token ot = null;
- String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
- requestUrl = requestUrl.replace("APPID", appId).replace("SECRET", appSecret).replace("CODE", code);
- logger.info("requestUrl"+requestUrl);
-
- JSONObject jsonObject = HttpRequestUtil.httpRequestJSONObject(requestUrl, HttpRequestUtil.GET_METHOD, null);
- if(null != jsonObject){
- try {
- ot = new Oauth2Token();
- ot.setAccessToken(jsonObject.getString("access_token"));
- ot.setExpiresIn(jsonObject.getInt("expires_in"));
- ot.setRefreshToken(jsonObject.getString("refresh_token"));
- ot.setOpenId(jsonObject.getString("openid"));
- ot.setScope(jsonObject.getString("scope"));
- } catch (Exception e) {
- int errorCode = jsonObject.getInt("errcode");
- String errorMsg = jsonObject.getString("errmsg");
- logger.info("获取网页授权凭证失败,错误码:"+errorCode+",错误提示:"+errorMsg);
- }
- }
- return ot;
- }
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,可以拉取到全部信息
- public class SNSUserInfo {
-
- private String openid;
-
- private String nickname;
-
- private String sex;
-
- private String country;
-
- private String province;
-
- private String city;
-
- private String headimgurl;
-
- private List<String> privilege;
-
- private String unionid;
-
- public String getOpenid() {
- return openid;
- }
- public void setOpenid(String openid) {
- this.openid = openid;
- }
- public String getNickname() {
- return nickname;
- }
- public void setNickname(String nickname) {
- this.nickname = nickname;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- public String getCountry() {
- return country;
- }
- public void setCountry(String country) {
- this.country = country;
- }
- 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 getHeadimgurl() {
- return headimgurl;
- }
- public void setHeadimgurl(String headimgurl) {
- this.headimgurl = headimgurl;
- }
- public List<String> getPrivilege() {
- return privilege;
- }
- public void setPrivilege(List<String> privilege) {
- this.privilege = privilege;
- }
- public String getUnionid() {
- return unionid;
- }
- public void setUnionid(String unionid) {
- this.unionid = unionid;
- }
- }
-
-
-
-
-
- public SNSUserInfo getSNSUserInfo(String accessToken, String openId) {
- SNSUserInfo suser = null;
- String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
- requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
-
- JSONObject jsonObjet = HttpRequestUtil.httpRequestJSONObject(requestUrl, HttpRequestUtil.GET_METHOD, null);
- if(null != jsonObjet){
- try {
- suser = new Gson().fromJson(jsonObjet.toString(), SNSUserInfo.class);
- } catch (JsonSyntaxException e) {
- logger.info("transfer exception");
- throw e;
- }
- }
- return suser;
- }
获取到SNSUserInfo之后,可以选择与数据库的用户绑定。
如果想解绑网站账号的话,可以学中信的公众号一样加个安全设置再解绑,相应的把openid从关联的用户表删除,可以加个绑定和解绑的时间日志。
问:如果PC端网站想绑定微信等第三方,把第一步的那个url作为场景ID生成一个临时的带参二维码,扫描之后输入网站的用户名密码就可以与公众号绑定了。试问是这样做的吗?