zoukankan      html  css  js  c++  java
  • 微信公众号授权登录

    1、配置服务器信息

    * 基本配置/ 填写服务器配置    按提示输入信息,这个环节需要注意的是token微信会在线验证,提前写好拦截器

    拦截器代码

    /***
     * 微信验签拦截器
     */
    public class WxAuthenticationInterceptor implements HandlerInterceptor {
        /**
         * 控制验签系统开闭
         */
        private final Boolean isOpen;
    
        public WxAuthenticationInterceptor(Boolean isOpen) {
            this.isOpen = isOpen;
        }
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            if (isOpen){
                // 只拦截method级别的处理器
                if (!(handler instanceof HandlerMethod)) return true;
                // 只拦截token注解过的方法
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                Method method = handlerMethod.getMethod();
                // 判断接口是否需要验签
                WxSign signAnnotation = method.getAnnotation(WxSign.class);
                if (signAnnotation != null){
                    String url = RequestUtil.getParameters(request);
    
                    if (StringUtils.isNotBlank(request.getParameter("signature"))) {
                        String signature = request.getParameter("signature");
                        String timestamp = request.getParameter("timestamp");
                        String nonce = request.getParameter("nonce");
                        String echostr = request.getParameter("echostr");
                        //LOGGER.info("signature[{}], timestamp[{}], nonce[{}], echostr[{}]", signature, timestamp, nonce, echostr);
                        if (SignUtil.checkSignature(signature, timestamp, nonce)) {
                            System.err.println(url + "数据源为微信后台,将echostr["  + echostr +  "]返回!");
                  return true;
    }else{ throw new InfoException("验签错误"); } }else{ throw new InfoException("验签失败"); } } } return true; } }

    验证地址

    @WxSign
    @GetMapping(value = {"","wxVerify"})
    @ResponseBody
    public String index(HttpServletRequest request){
    String echostr = request.getParameter("echostr");
    return echostr;
    }

    SignUtil.java

    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Arrays;
    
    public class SignUtil {
    
        private static String token = "jiangxinpai";//这里是自定义的token,需和你提交的token一致
    
        /**
         * 校验签名
         *
         * @param signature
         *            签名
         * @param timestamp
         *            时间戳
         * @param nonce
         *            随机数
         * @return 布尔值
         */
        public static boolean checkSignature(String signature, String timestamp, String nonce) {
            String checktext = null;
            if (null != signature) {
                // 对ToKen,timestamp,nonce 按字典排序
                String[] paramArr = new String[] { token, timestamp, nonce };
                Arrays.sort(paramArr);
                // 将排序后的结果拼成一个字符串
                String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
    
                try {
                    MessageDigest md = MessageDigest.getInstance("SHA-1");
                    // 对接后的字符串进行sha1加密
                    byte[] digest = md.digest(content.toString().getBytes());
                    checktext = byteToStr(digest);
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                }
            }
            // 将加密后的字符串与signature进行对比
            return checktext != null ? checktext.equals(signature.toUpperCase()) : false;
        }
    
        /**
         * 将字节数组转化为16进制字符串
         *
         * @param byteArrays
         *            字符数组
         * @return 字符串
         */
        private static String byteToStr(byte[] byteArrays) {
            String str = "";
            for (int i = 0; i < byteArrays.length; i++) {
                str += byteToHexStr(byteArrays[i]);
            }
            return str;
        }
    
        /**
         * 将字节转化为十六进制字符串
         *
         * @param myByte
         *            字节
         * @return 字符串
         */
        private static String byteToHexStr(byte myByte) {
            char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
            char[] tampArr = new char[2];
            tampArr[0] = Digit[(myByte >>> 4) & 0X0F];
            tampArr[1] = Digit[myByte & 0X0F];
            String str = new String(tampArr);
            return str;
        }
    
    }

    2.获取accessToken, OAuth过程

    @GetMapping("/oauth")
        public String oauth(HttpServletRequest request, HttpServletResponse response, String code, String state){
            //code说明 : code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
            /*错误返回码说明如下:
            返回码    说明
            10003    redirect_uri域名与后台配置不一致
            10004    此公众号被封禁
            10005    此公众号并没有这些scope的权限
            10006    必须关注此测试号
            10009    操作太频繁了,请稍后重试
            10010    scope不能为空
            10011    redirect_uri不能为空
            10012    appid不能为空
            10013    state不能为空
            10015    公众号未授权第三方平台,请检查授权状态
            10016    不支持微信开放平台的Appid,请使用公众号Appid*/
            WxAccessToken wxAccessToken = WxApiUtil.getAccessToken(code);
            if(wxAccessToken != null){
                String userIp = RequestUtil.getIp(request);
    
                WxUserInfo userInfo = WxApiUtil.getUserInfo(wxAccessToken.getAccess_token(), wxAccessToken.getOpenid());
                if(userInfo != null){
                    //预注册账号
                   try {
                       User user = userFacadeService.registerWithWx(wxAccessToken.getOpenid(), wxAccessToken.getAccess_token()
                               , userInfo.getNickname(), userInfo.getHeadimgurl(), userIp);
                       if(user != null) {
                           try {
                               response.sendRedirect(Constant.AppUrl  + "/pages/user/bootstrap/bind?userId=" + user.getUserId() + "");
                           } catch (IOException e) {
                               e.printStackTrace();
                           }
                       }
                   }catch (Exception e){
                       try {
                           response.sendRedirect(Constant.AppUrl  + "/pages/user/bootstrap/login?pop=" + e.getMessage());
                       } catch (IOException ex) {
                           ex.printStackTrace();
                       }
                   }
    
                }
            }
            try {
                response.sendRedirect(Constant.AppUrl  + "/pages/user/bootstrap/login?pop=" + "微信登录授权失败");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "ERROR";
        }

    WxApiUtil.java

    public class WxApiUtil {
        private final static String appId = "";
        private final static String appSecret = "";
    
        public static String getAccessToken(){
            /*grant_type    是    获取access_token填写client_credential
            appid    是    第三方用户唯一凭证
            secret    是    第三方用户唯一凭证密钥,即appsecret*/
            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
            String response = HttpUtil.get(url, null);
            return response;
        }
    
        public static void main(String[] args) {
            String accessToken = WxApiUtil.getAccessToken();
            System.out.println(accessToken);
        }
    
        public static WxAccessToken getAccessToken(String code) {
            String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + appSecret + "&code=" + code+ "&grant_type=authorization_code";
            String response = HttpUtil.get(url, null);
            /*{
                "access_token":"ACCESS_TOKEN",
                    "expires_in":7200,
                    "refresh_token":"REFRESH_TOKEN",
                    "openid":"OPENID",
                    "scope":"SCOPE"
            }*/
            if(!response.contains("errcode")){
                WxAccessToken wxAccessToken = JsonUtil.getModel(response, WxAccessToken.class);
                return wxAccessToken;
            }else {
                System.err.println("getAccessToken:" + response);
            }
            return null;
        }
    
    
        public static WxUserInfo getUserInfo(String accessToken, String openId){
            /*{
                "openid":" OPENID",
                    " nickname": NICKNAME,
                    "sex":"1",
                    "province":"PROVINCE"
                "city":"CITY",
                    "country":"COUNTRY",
                    "headimgurl":       "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
                    "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
                "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
            }*/
            String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+ accessToken + "&openid=" + openId + "&lang=zh_CN";
            String response = HttpUtil.get(url, null);
            if(!response.contains("errcode")){
                WxUserInfo wxUserInfo = JsonUtil.getModel(response, WxUserInfo.class);
                return wxUserInfo;
            }else{
                System.err.println("getUserInfo:" + response);
            }
            return null;
        }
    }

    到此就完成任务啦~  微信用户打开H5后请求获取用户信息,无感预注册账户,等到授权结束后再让用户绑定手机号推广码等等信息,如果报错了就重定向弹窗告知用户。

  • 相关阅读:
    POJ-3254 + POJ-1185 状压DP入门题
    POJ-3667 线段树区间合并入门题
    HDU-4507 数位DP 记录一个毒瘤错误orz
    HDU-4734 F(x)数位dp
    HDU-3709 Balanced Number 数位dp+枚举
    分块入门 LibreOJ分块九题
    HDU-4389 X mod f(x) && 2018上海大都会邀请赛J 数位dp
    HDU-3038 How Many Answers Are Wrong (带权并查集)
    Codeforces 608B Hamming Distance Sum (前缀和)
    (二十六 )数据库:水平切分,数据库秒级扩容!
  • 原文地址:https://www.cnblogs.com/renhongwei/p/10516850.html
Copyright © 2011-2022 走看看