微信授权登录——OAuth2.0

 

   如果用户在微信客户端中访问我公司的网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。 整个流程是这样的:

 

 在这个过程中 最重要的一步 是 获取openID和 unionId   ,我把这次 请求返回的数据封装成一个对象(AccessTokenBean),然后根据openID到本地的数据库查询有没有这一条数据,如果没有就使用 unionID机制查询,这里需要详细的讲解一下,我当时就对这一点很迷惑。

   (这些问答是我刚开始的时候遇到的,到后来慢慢解决了的)

  Q: 首先 openID是什么? 

  A: openId 是 用户唯一标识,用户访问公众号的网页,产生一个用户和公众号唯一的OpenID,这个ID的存在表示这个用户在本网站登录过,并且用户同意微信授权登录。

 

  Q: 什么是授权临时票据?

  A:第三方通过code进行获取access_token的时候需要用到,code的超时时间为10分钟,一个code只能成功换取一次access_token即失效。code的临时性和一次保障了微信授权登录的安全性。第三方可通过使用https和state参数,进一步加强自身授权登录的安全性。

 

  Q: 什么是unionID?

  A:   只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。详见:获取用户个人信息(UnionID机制) 比如说 我公司有两个app 产品(a产品,b产品), 我在公众号里面, 授权微信登录了a ,如果我想再登录b,这时候就需要查看数据库里面有没有AccessTokenBean 的unionId,如果有则直接静默登录,提高了用户体验度。

 

  Q: 能从微信那里获取到哪些用户的信息

  A: 用户的头像,昵称,省市,性别

 

  Q: 为什么要使用 OAuth 2.0 ?

  A: 用户既然已经使用微信访问到自己网站了,就可以用微信账户直接登录我的网站,省去了用户填写信息注册的步骤 ,提高了用户体验。

 

代码部分:

      前端需要从微信获取 一个code,然后用这个code 来换取  AccessTokenBean 对象,这个对象包括,openId ,unionId 等其他信息。

    // 前端有一个code  ,可以用这个code 换取token 和openID, unionID ,返回的是一个用户的ID
    // 查询用户信息
    @RequestMapping(value = "H5/getInformation", method = { RequestMethod.POST })
    @ResponseBody
    public GeneralResponse getInformation(HttpServletRequest request) throws IOException {

        // 根据code 到微信查询 openid 和unionID
        String jsonParam = IOUtils.toString(request.getInputStream(), "UTF-8");
        if (StringUtils.isBlank(jsonParam)) {
            return new GeneralResponse(900, "POST请求参数不能为空");
        }
        Map<String,String> req = JacksonUtil.json2Obj(jsonParam, Map.class);
        if (null ==req.get("code")){
            return new GeneralResponse(900, "code参数不能为空");
        }
        AccessTokenBean accessTokenBean= OAuth2Service.getAccessToken(req.get("code"));
        if(null ==accessTokenBean){
            return new GeneralResponse(900, "从微信获取openid 出错");
        }
        CommonResponse response = CommonResponse.generateOKCommonResponse();

        String openId = accessTokenBean.getOpenid();
        // 这里可以获取token 和 unionID
        if (StringUtils.isNotBlank(openId)) {
            // 根据openID检查有没有存在数据库中
            OauthUser oauthUser=new OauthUser();
            oauthUser.setOpenId(openId);
         List<OauthUser> userList=  oauthUserService.queryBySelective(oauthUser);
         if (!userList.isEmpty())
         {
             String  userId= userList.get(0).getUserId();
             User user= userService.getUserByUserId(userId);
             response.setData(user);
         }else
             { // 如果 openid  没有找到 则使用  unionId 来找
                 oauthUser.setOpenId(null);
                 oauthUser.setUnionId(accessTokenBean.getUnionId());
                 List<OauthUser> userList1=  oauthUserService.queryBySelective(oauthUser);
                 if (! userList1.isEmpty()){
                     String  userId =  userList1.get(0).getUserId();
                     // 如果找到了就,把这个openid 添加到数据库
                     addOauthUser(accessTokenBean.getOpenid(),accessTokenBean.getUnionId(),userId);
                     User user= userService.getUserByUserId(userId);
                     response.setData(user);
                 }else{
                     //从微信获取用户信息,,然后再 跳转到  注册界面
                   WXUserBean wxUserBean= OAuth2Service.getUserInfo(accessTokenBean);
                   User user=new User();
                   if (null != wxUserBean){
                       user.setPhotoUrl(wxUserBean.getHeadimgurl());
                       user.setAlias(wxUserBean.getNickname());
                       user.setSex(wxUserBean.getSex()); // 1 男
                   }
                     response.setData(user);
                 }
             }
        }
        return response;
    }

 

主要的类:  OAuth2Service  

import com.alibaba.fastjson.JSONObject;
import com.hupu.smart.elgame.api.dto.user.oauthuser.AccessTokenBean;
import com.hupu.smart.elgame.api.dto.user.oauthuser.WXUserBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;


/**
 * Created by admin 2017/4/18.
 */
@Service
public class OAuth2Service {


    @Value("#{configProperties['APP_ID']}")
    private static String APP_ID;

    @Value("#{configProperties['APP_SECRET']}")
    private static String APP_SECRET;


    /**
     * 获取微信用户信息
     * @param atBean
     * @return
     */
    public static WXUserBean getUserInfo(AccessTokenBean atBean) {
        if (!verify(atBean.getAccess_token(), atBean.getOpenid())) {
            atBean = refreshAccessToken(atBean.getRefresh_token());
        }
        WXUserBean userBean = getUserInfoApi(atBean.getAccess_token(),atBean.getOpenid());
        return userBean;
    }


    /**
     * 获取AccessToken
     * @param code
     * @return
     */
    public static AccessTokenBean getAccessToken(String code) {
        JSONObject jObj = Get.json("https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ APP_ID +"&secret="+ APP_SECRET +"&code="+ code +"&grant_type=authorization_code");
        AccessTokenBean oBean = new AccessTokenBean();
        if (null !=jObj.get("errcode")){
            return null;
            }
        oBean.setAccess_token(jObj.getString("access_token"));
        oBean.setExpires_in(jObj.getLong("expires_in"));
        oBean.setRefresh_token(jObj.getString("refresh_token"));
        oBean.setOpenid(jObj.getString("openid"));
        oBean.setScope(jObj.getString("scope"));
        oBean.setUnionId(jObj.getString("unionid"));
        return oBean;
    }

    /**
     * 刷新AccessToken
     * @param refresh_token
     * @return
     */
    private static AccessTokenBean refreshAccessToken(String refresh_token) {
        JSONObject jObj = Get.json("https://api.weixin.qq.com/sns/oauth2/refresh_token?appid="+ APP_ID +"&grant_type=refresh_token&refresh_token="+ refresh_token);
        AccessTokenBean oBean = new AccessTokenBean();
        oBean.setAccess_token(jObj.getString("access_token"));
        oBean.setExpires_in(jObj.getLong("expires_in"));
        oBean.setRefresh_token(jObj.getString("refresh_token"));
        oBean.setOpenid(jObj.getString("openid"));
        oBean.setScope(jObj.getString("scope"));
        return oBean;
    }

    /**
     * 验证AccessToken是否可用
     * @param accessToken
     * @param openid
     * @return
     */
    private static boolean verify(String accessToken,String openid) {
        JSONObject jObj = Get.json("https://api.weixin.qq.com/sns/auth?access_token="+ accessToken +"&openid=" + openid);
        return jObj.getInteger("errcode") == 0;
    }

    /**
     * 获取用户信息
     * @param accessToken
     * @param openid
     * @return
     */
    private static WXUserBean getUserInfoApi(String accessToken, String openid) {
        JSONObject jObj = Get.json("https://api.weixin.qq.com/sns/userinfo?access_token="+ accessToken +"&openid="+ openid +"&lang=zh_CN");
        WXUserBean wxub = new WXUserBean();
        wxub.setOpenid(jObj.getString("openid"));
        wxub.setNickname(jObj.getString("nickname"));
        wxub.setSex(jObj.getInteger("sex"));
        wxub.setProvince(jObj.getString("province"));
        wxub.setCity(jObj.getString("city"));
        wxub.setCountry(jObj.getString("country"));
        wxub.setHeadimgurl(jObj.getString("headimgurl"));
        wxub.setUnionid(jObj.getString("unionid"));
        return wxub;
    }


}

 

最后还有两个实体类:

public class WXUserBean {

    private String openid;
    private String nickname;
    private int sex;
    private String province;
    private String city;
    private String country;
    private String headimgurl;
    private String unionid;

    (省去get,set 方法)

}
 
public class AccessTokenBean {

    private String access_token;
    private String refresh_token;
    private String openid;
    private long expires_in;
    private String scope;
    private String unionId;
   (省去,get 和set 方法)        

}

 

posted @ 2017-04-21 15:57  慕容哲别--  阅读(766)  评论(0编辑  收藏  举报