【公衆號】微信進入公衆號鏈接自動獲取授權登陸

前言

最近項目上有一個需求,用戶反映每次從微信打開鏈接都需要手動登陸,比較繁瑣,想點開微信連接後自動登陸,加快審批操作。接到這個需求一開始想的是平時在刷微信公衆號的時候,進一些第三方應用網頁會要求授權,之後就不需要登陸了。順着這個思路,在網上百度了一下,瞭解到微信網頁開發中的一個網頁授權。經過一系列測試發現是可用的,特此記錄。本文僅限測試公衆號,後續企業公衆號項目上線再來回顧。

  • 本文采用的是綁定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月的尾巴

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章