• 微信授权登录——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 方法)        
    
    }
  • 相关阅读:
    Python--my first try!
    AB PLC首次IP地址如何分配
    如何解压DMK固件
    罗克韦尔自动化官网如何下载设备固件
    如何使用AB PLC仿真软件Studio 5000 Logix Emulate
    Studio 5000指令IN_OUT管脚实现西门子风格
    AB PLC分类
    罗克韦尔自动化发展简史
    C#曲线分析平台的制作(五,Sqldependency+Signalr+windows 服务 学习资料总结)
    自动化监控上位机系统二次开发之我见
  • 原文地址:https://www.cnblogs.com/murong/p/6743995.html
Copyright © 2020-2023  润新知