【公众号】微信进入公众号链接自动获取授权登陆

前言

最近项目上有一个需求,用户反映每次从微信打开链接都需要手动登陆,比较繁琐,想点开微信连接后自动登陆,加快审批操作。接到这个需求一开始想的是平时在刷微信公众号的时候,进一些第三方应用网页会要求授权,之后就不需要登陆了。顺着这个思路,在网上百度了一下,了解到微信网页开发中的一个网页授权。经过一系列测试发现是可用的,特此记录。本文仅限测试公众号,后续企业公众号项目上线再来回顾。

  • 本文采用的是绑定openid 到 系统中的用户,因此登陆和授权二者都要通过,绑定之后便可以自动登陆。

一、准备

  • 1.需要一个测试公众号
    申请了个人公众号之后,在左侧菜单栏中,进入开发者工具 》选择公众号测试帐号

在这里插入图片描述
我们需要的是APPIDappsecret

然后往下滑动,到网页服务栏中,设置网页帐号

在这里插入图片描述
单击后面的修改,配置回调的域名,测试账号是支持设置ip的,如果是在本地开发,我们可以设置为127.0.0.1,注意不需要添加http之类的。域名则只用填写域名。

  • 2.微信web开发者调试工具
    这个只用去官网下载即可;这个工具可以在开发时,模拟手机微信访问链接,进行授权。

二、开发

2.1 搭建项目

项目结构SpringBoot + Mybatis + Themeleaf

  • 1.pom依赖
   <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <!--<version>8.0.11</version>-->
            <version>5.1.47</version>
        </dependency>
        
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.1</version>
        </dependency>

        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.2.3</version>
            <classifier>jdk15</classifier><!-- jdk版本 -->
        </dependency>
        
    <dependency>
    <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.2.1</version>
        </dependency>

        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>


        <!-- 引入thymeleaf模板引擎-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

    </dependencies>
    
     <build>
        <resources>
            <resource>
                <directory>src/main/java</directory><!--java文件的路径-->
                <includes>
                    <include>**/*.*</include>
                </includes>
                <!-- <filtering>false</filtering>-->
            </resource>
            <resource>
                <directory>src/main/resources</directory><!--资源文件的路径-->
                <includes>
                    <include>**/*.*</include>
                </includes>
                <!-- <filtering>false</filtering>-->
            </resource>
        </resources>
    </build>
  • 2.启动类
@SpringBootApplication
@MapperScan("com.dao")
@ServletComponentScan("com.filter")
public class App_80 {
    public static void main(String[] args) {
        SpringApplication.run(App_80.class);
    }

}

  • 3.配置文件application.yml
server:
  port: 80  #80端口是因为回调地址如果带端口是报错,80端口可以直接用127.0.0.1访问

logging:
  level:
    com.dao: DEBUG

mybatis:
  mapper-locations: classpath:mapper/**/*.xml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db_ads?serverTimezone=UTC&useSSL=false
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: xx
    hikari:
      minimum-idle: 3
      maximum-pool-size: 10
      max-lifetime: 30000
      connection-test-query: SELECT 1

  thymeleaf:
#    prefix: classpath:/templates
#    suffix: .html
    encoding: utf-8
    check-template: true
    cache: false

3.其他包括登陆用户实体类,mapper文件,service等;由于篇幅限制,部分类均最后贴上

2.2 WeixinUtil 工具

这个类基本上用来和微信api交互,所以我们封装成一个util

public class WeixinUtil {
    static Logger log = LoggerFactory.getLogger(WeixinUtil.class);

    //则scope为snsapi_base不会跳页面 snsapi_userinfo 会弹出页面
    private static String auth_url  = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=[appid]&redirect_uri=[projectUrl]/getOpenInfo/[redirectUrl]&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
    //其他url
    public final static String getOpen_id_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
    public final static String getNewAccess_token = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";
    //公众号的配置
    public static String appid = "wx5eb3c26d6d692516";
    public static String appsecret = "00b5715e2542ec74a2dac31b12cfae4a";
    public static String websiteAndProject = "http://121.43.230.40"; //项目地址
    //回调地址记录,可能部分地址带有参数,避免参数不识别等问题
    private static volatile Map<String,String>  urlMap = new ConcurrentHashMap<>();

    /**
     * 将需要访问的地址置入map中,以md5作为key
     * @param url
     * @return
     * @throws Exception
     */
    public static String setUrl(String url) throws Exception {
        if(StringUtils.isEmpty(url)){ throw new Exception("访问地址为空"); }
        String md5Key = DigestUtils.md5DigestAsHex(url.getBytes());
        urlMap.put(md5Key,url);
        return md5Key;
    }

    /**
     * 根据md5获取访问的全路径
     * @param key
     * @return
     * @throws Exception
     */
    public static String getUrl(String key) throws Exception {
        if(StringUtils.isEmpty(key)){ throw new Exception("key为空"); }
        String url = urlMap.get(key);
        return websiteAndProject + url;
    }

    /**
     * 获取授权地址,拼接
     * @param urlCode 回调地址的md5key
     * @return
     */
    public static String getAuthUrl(String urlCode){
        return auth_url.replace("[appid]",appid).replace("[projectUrl]",websiteAndProject).replace("[redirectUrl]",urlCode);
    }

    /**
     * 发起https请求并获取结果
     * @param requestUrl 请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr 提交的数据
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
     */
    public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();
        try {
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = { new MyX509TrustManager() };
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);
            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            httpUrlConn.setRequestMethod(requestMethod);
            if ("GET".equalsIgnoreCase(requestMethod))
                httpUrlConn.connect();
            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式,防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
            jsonObject = JSONObject.fromObject(buffer.toString());
        } catch (ConnectException ce) {
            log.error("Weixin server connection timed out.");
        } catch (Exception e) {
            log.error("https request error:{}", e);
        }
        return jsonObject;
    }

    /**
     * 获得用户基本信息
     * @param request
     * @param code
     * @param appid
     * @param appsecret
     * @return
     */
    public static OpenIdResult getOpenId(HttpServletRequest request, String code, String appid, String appsecret) {
        String requestURI = request.getRequestURI();
        String param = request.getQueryString();
        if(param!=null){
            requestURI = requestURI+"?"+param;
        }
        String url = getOpen_id_url.replace("APPID",appid).replace("SECRET",appsecret).replace("CODE",code);
        JSONObject jsonObject = httpRequest(url, "POST", null);
        OpenIdResult result = new OpenIdResult();
        if (null != jsonObject) {
            Object obj = jsonObject.get("errcode");
            if (obj == null) {
                result.setAccess_token(jsonObject.getString("access_token"));
                result.setExpires_in(jsonObject.getString("expires_in"));
                result.setOpenid(jsonObject.getString("openid"));
                result.setRefresh_token(jsonObject.getString("refresh_token"));
                result.setScope(jsonObject.getString("scope"));
            }else{
                System.out.println("获取openId回执:"+jsonObject.toString()+"访问路径:"+requestURI);
                log.error("访问路径:"+requestURI);
                log.error("获取openId失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
            }
        }
        return result;
    }

  /**
     * 检验授权凭证(access_token)是否有效
     * @param accessToken 凭证
     * @param openid id
     * @return
     */
    public static int checkAccessToken(String accessToken, String openid) {
        String requestUrl = "https://api.weixin.qq.com/sns/auth?access_token="+accessToken+"&openid="+openid;
        JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
        int result = 1;
        // 如果请求成功
        if (null != jsonObject) {
            try {
                result = jsonObject.getInt("errcode");
            } catch (JSONException e) {
                accessToken = null;
                // 获取token失败
                log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
            }
        }
        return result;
    }
    /**
     * 用户授权,使用refresh_token刷新access_token
     * @return
     */
    public static OpenIdResult getNewAccess_Token(OpenIdResult open,String refresh_token,String openId) {
        String requestUrl = getNewAccess_token.replace("REFRESH_TOKEN", refresh_token).replace("APPID", openId);
        JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
        // 如果请求成功
        if (null != jsonObject) {
            try {
                open.setAccess_token(jsonObject.getString("access_token"));
            } catch (JSONException e) {
                // 获取token失败
                log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
            }
        }
        return open;
    }

    
    
    /**
     * 通过网页授权获取用户信息
     * @param accessToken 网页授权接口调用凭证
     * @param openId 用户标识
     * @return WeixinUserInfo
     */
    public static WeixinUserInfo getWeixinUserInfo(String accessToken, String openId) {
        WeixinUserInfo user = null;

        // 拼接请求地址
        String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
        requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
        // 通过网页授权获取用户信息
        JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
        if (null != jsonObject) {
            try {
                user = new WeixinUserInfo();
                // 用户的标识
                user.setOpenId(jsonObject.getString("openid"));
                // 昵称
                user.setNickname(jsonObject.getString("nickname"));
                // 性别(1是男性,2是女性,0是未知)
                user.setSex(jsonObject.getInt("sex"));
                // 用户所在国家
                user.setCountry(jsonObject.getString("country"));
                // 用户所在省份
                user.setProvince(jsonObject.getString("province"));
                // 用户所在城市
                user.setCity(jsonObject.getString("city"));
                // 用户头像
                user.setHeadImgUrl(jsonObject.getString("headimgurl"));
                // 用户特权信息
                user.setPrivilegeList(JSONArray.toList(jsonObject.getJSONArray("privilege"), List.class));
            } catch (Exception e) {
                user = null;
                int errorCode = jsonObject.getInt("errcode");
                String errorMsg = jsonObject.getString("errmsg");
                log.error("获取用户信息失败 errcode:{} errmsg:{},reqUrl{}", errorCode, errorMsg);
            }
        }
        return user;
    }
}

2.3 回调接口与登陆接口

回调接口是指,获取授权成功之后微信需要调用该接口传递code等数据,因此需要写一个controller来接收微信的回调。该接口的mapping也是对应获取授权地址中的redirect_uri参数。
如本项目中,定义为&redirect_uri=[projectUrl]/getOpenInfo/[redirectUrl]&因此我们的mapping就是getOpenInfo/{redirectUr}

@Controller
public class WxController {
   Logger log = LoggerFactory.getLogger(WxController.class);

   @Autowired
   UserService userService;


    /**
     * 微信网页授权获得微信详情
     * @param code
     * @param state
     * @param redirect 授权后跳转的视图 md5 key
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @RequestMapping("/getOpenInfo/{redirect}")
    public void getOpenInfo(Model model, @RequestParam("code") String code, @RequestParam("state") String state, @PathVariable("redirect") String redirect, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        log.error("授权成功回调");
        HttpSession session = request.getSession();
        User user = (User)session.getAttribute("C_USER");
        // 用户同意授权
        if (!"authdeny".equals(code)) {
            //获取OpenId
            OpenIdResult open = WeixinUtil.getOpenId(request, code, WeixinUtil.appid, WeixinUtil.appsecret);

            //检验授权凭证(access_token)是否有效,如果需要微信的用户信息,可以去掉这些注释
       /*     int result = WeixinUtil.checkAccessToken(open.getAccess_token(), open.getOpenid());
            if(0 != result){
                open = WeixinUtil.getNewAccess_Token(open,open.getRefresh_token(),TimedTask.appid);
            }*/
            // 网页授权接口访问凭证
           // String accessToken = open.getAccess_token();
            String openId = open.getOpenid();
            //获取微信用户详细信息,如果你不需要授权,可跳过该步骤,直接以微信的OpenId,查找是否已经绑定,没有跳转到绑定界面
            //WeixinUserInfo wxUser = WeixinUtil.getWeixinUserInfo(accessToken, openId);

            //从数据库获取当前微信绑定的用户
            User customer = userService.getUserByOpenId(open.getOpenid());
            log.error("数据库的用户" + customer);
            if(customer!=null){//当前用户已经绑定了
                if(customer.getStatus()==2){ //用户不可用
                    response.sendRedirect("/error/用户不可用");
                    return ;
                }else {
                    session.setAttribute("C_USER",customer);
                }
                //customer.setHeadPhoto(user.getHeadImgUrl());
            }else{
                log.error("未绑定用户");
               //未绑定用户,判断是否登陆,如果未登陆还要登陆
                if(user == null){
                    //未登陆前往登陆
                    response.sendRedirect("/toLogin/"+redirect);
                    return ;
                }else{
                    user.setOpenId(openId);
                    //绑定
                    userService.updateUser(user);
                    session.setAttribute("C_USER",user);
                }

            }
            session.setAttribute("C_OPENID", open);
            response.setContentType("text/html; charset=UTF-8");
            try {
                response.sendRedirect(WeixinUtil.getUrl(redirect));
            } catch (Exception e) {
                e.printStackTrace();
            }
          return ;
        }else{
            response.setContentType("text/html; charset=UTF-8");
            try {
                response.sendRedirect("/error/"+"取消授权");
            } catch (IOException e) {
                e.printStackTrace();
            }
        return ;
        }
    }

登陆处理

@Controller
public class LoginController {

    @Autowired
    UserService userService;

    /**
     * 登陆或者注册
     * @param userName
     * @param passWord
     * @param model
     * @return
     */
    @PostMapping("/login")
    public void login(HttpServletRequest request, HttpServletResponse response,String userName, String passWord, Model model, String redirect) throws IOException, ServletException {
        HttpSession session = request.getSession();
        User user = new User().setUserName(userName).setPassWord(passWord);
        try{
            User newUser = userService.loginOrRegister(user);
            model.addAttribute("user",newUser);
            session.setAttribute("C_USER",newUser);
            if(StringUtils.isBlank(redirect)){
                redirect = "home";
            }
            session.removeAttribute("login_msg");
            response.sendRedirect(WeixinUtil.getUrl(redirect));
        }catch (Exception e){
            e.printStackTrace();
            // model.addAttribute("msg",e.getMessage());
            //request.getRequestDispatcher("/toLogin/" + redirect).forward(request,response);
            session.setAttribute("login_msg",e.getMessage());
            response.sendRedirect("/toLogin/"+redirect);
            return;
        }
    }


    @RequestMapping("/logout")
    public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        HttpSession session = request.getSession();
        session.invalidate();
        response.sendRedirect("/");
    }

}

  • 页面跳转
@Controller
public class PageController {
    /**
     * 首页
     * @param model
     * @return
     */
    @GetMapping("home")
    public String toHome(Model model){
        model.addAttribute("code",200);
        model.addAttribute("msg","hello world");
        return "home";
    }

    /**
     * 登陆页面
     * @param model
     * @return
     */
    @GetMapping("toLogin/{redirect}")
    public String toLogin(Model model, @PathVariable String redirect){
        model.addAttribute("redirect",redirect);
        return "login";
    }

    /**
     * 登陆页面
     * @param model
     * @return
     */
    @RequestMapping("toLogin/")
    public String toLoginWitOutRedict(Model model){
        return "login";
    }

    /**
     * 错误页面
     * @param model
     * @return
     */
    @RequestMapping("error/{msg}")
    public String toError(Model model, @PathVariable String msg){
        model.addAttribute("msg",msg);
        return "unerror";
    }
}

2.4 过滤器自动登陆

我们可以对需要登陆的地方添加过滤器从而进行自动登陆或者是权限管理。

/**
 * 微信过滤器
 * 自动获取授权
 */
@WebFilter(value = "/user/*")
public class WxFilter implements Filter {

    Logger log = LoggerFactory.getLogger(WxFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse hsResponse = (HttpServletResponse) response;
        String requestURI = httpRequest.getRequestURI();
        HttpSession session = httpRequest.getSession();
        //获取登陆用户标记
        User user = (User) session.getAttribute("C_USER");
        //获取授权标记
        OpenIdResult result = (OpenIdResult) session.getAttribute("C_OPENID");
        //不是手机端判断是否登陆
        try {
            if (!JudgeIsMoblie(httpRequest)) {
                if (user == null) {
                    String urlKey = WeixinUtil.setUrl(requestURI);
                    //跳到登陆页面
                    httpRequest.getRequestDispatcher("/toLogin/" + urlKey).forward(request, response);
                    return;
                }
                filterChain.doFilter(request, response);
                return;
            }


            //已经授权过 放行 未授权还要获取授权
            if (result != null) {
                //自动登陆
                if (user == null) {
                    User customer = new UserService().getUserByOpenId(result.getOpenid());
                    if (customer != null) {
                        session.setAttribute("C_USER", customer);
                    } else {
                        String urlKey = WeixinUtil.setUrl(requestURI);
                        //跳到登陆页面
                        httpRequest.getRequestDispatcher("/toLogin/" + urlKey).forward(request, response);
                        return;
                    }
                }
                filterChain.doFilter(request, response);
                return;
            }

            //获取访问地址
            if (requestURI.contains("getOpenInfo")) {//认证地址 放行
                filterChain.doFilter(request, response);
                return;
            }
            log.error("微信未授权");
            //调用微信授权,记录回调url
            String urlCode = WeixinUtil.setUrl(requestURI);
            hsResponse.sendRedirect(WeixinUtil.getAuthUrl(urlCode));
        } catch (Exception e) {
            e.printStackTrace();
            hsResponse.sendRedirect("/error/" + e.getMessage());
        }

    }


    //判断是否为手机浏览器
    public boolean JudgeIsMoblie(HttpServletRequest request) {
        boolean isMoblie = false;
        String[] mobileAgents = {"iphone", "android", "ipad", "phone", "mobile", "wap", "netfront", "java", "opera mobi",
                "opera mini", "ucweb", "windows ce", "symbian", "series", "webos", "sony", "blackberry", "dopod",
                "nokia", "samsung", "palmsource", "xda", "pieplus", "meizu", "midp", "cldc", "motorola", "foma",
                "docomo", "up.browser", "up.link", "blazer", "helio", "hosin", "huawei", "novarra", "coolpad", "webos",
                "techfaith", "palmsource", "alcatel", "amoi", "ktouch", "nexian", "ericsson", "philips", "sagem",
                "wellcom", "bunjalloo", "maui", "smartphone", "iemobile", "spice", "bird", "zte-", "longcos",
                "pantech", "gionee", "portalmmm", "jig browser", "hiptop", "benq", "haier", "^lct", "320x320",
                "240x320", "176x220", "w3c ", "acs-", "alav", "alca", "amoi", "audi", "avan", "benq", "bird", "blac",
                "blaz", "brew", "cell", "cldc", "cmd-", "dang", "doco", "eric", "hipt", "inno", "ipaq", "java", "jigs",
                "kddi", "keji", "leno", "lg-c", "lg-d", "lg-g", "lge-", "maui", "maxo", "midp", "mits", "mmef", "mobi",
                "mot-", "moto", "mwbp", "nec-", "newt", "noki", "oper", "palm", "pana", "pant", "phil", "play", "port",
                "prox", "qwap", "sage", "sams", "sany", "sch-", "sec-", "send", "seri", "sgh-", "shar", "sie-", "siem",
                "smal", "smar", "sony", "sph-", "symb", "t-mo", "teli", "tim-", "tosh", "tsm-", "upg1", "upsi", "vk-v",
                "voda", "wap-", "wapa", "wapi", "wapp", "wapr", "webc", "winw", "winw", "xda", "xda-",
                "Googlebot-Mobile"};
        if (request.getHeader("User-Agent") != null) {
            String agent = request.getHeader("User-Agent");
            for (String mobileAgent : mobileAgents) {
                if (agent.toLowerCase().indexOf(mobileAgent) >= 0 && agent.toLowerCase().indexOf("windows nt") <= 0 && agent.toLowerCase().indexOf("macintosh") <= 0) {
                    isMoblie = true;
                    break;
                }
            }
        }
        return isMoblie;
    }

}

2.4 其他类

  • 微信用户
@Data
public class WeixinUserInfo {
    private String openId;
    private String nickname;
    private Integer sex;
    private String country;
    private String province;
    private String city;
    private String headImgUrl;
    private List privilegeList;
}

  • OpenIdResult
@Data
public class OpenIdResult {
    private String access_token;
    private String expires_in; 
    private String refresh_token; 
    private String openid; //用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
    private String scope; //用户授权的作用域,使用逗号(,)分隔 
}

  • MyX509TrustManager
public class MyX509TrustManager implements X509TrustManager {
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException
    {
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException
    {
    }

    public X509Certificate[] getAcceptedIssuers()
    {
        return null;
    }
}

还有一些mapper和servie,页面以及sql均放github(文末地址)上了。需要自取

2.5 测试

如果需要手机端也可以访问,则需要部署在服务器上,同时也要修改项目路径和回调地址。由于本次是测试项目,则写在代码中,如若正式开发,还是写在配置文件中比较好。

在这里插入图片描述

首次访问该项目,首页无账号信息。

在这里插入图片描述
进入需要权限的地址,由于未登陆且当前未绑定,因此需要登陆
在这里插入图片描述

登陆成功之后,后台会自动绑定,我们也可以看到当前登陆用户的信息,然后点击退出,清除session信息。
在这里插入图片描述
重新打开该页面,可以发现首页已经有账号信息了,且进入权限页面也不需要登陆。

三、总结

整体流程如下,由于不好处理授权与登陆先后的关系,因此回调重定向的页面都会有点多。有更好方案的欢迎评论区讨论。后续可以对接项目主动推送链接给用户以及菜单栏等操作。

在这里插入图片描述

体验链接:http://121.43.230.40 (有效期2020-10-12,阿里云学生服务器,未配置域名,电脑访问无效果)
需关注测试公众号才可获取授权:

在这里插入图片描述

GitHub项目地址:https://github.com/LiCQing/WeiXinWebAuthDemo

CSDN资源:

2020-5月的尾巴

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值