• 玩玩微信公众号Java版之六:微信网页授权


    我们经常会访问一些网站,用微信登录的时候需要用到授权,那么微信网页授权是怎么一回事呢,一起来看看吧!
     
     
    官方的文档有很详细的说明,这里就主要分析重要的几点:
    第一,网页授权分类及说明:
    1、以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
    2、以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。
     
    第二,网页授权流程分为四步:
    1、引导用户进入授权页面同意授权,获取code 
    2、通过code换取网页授权access_token(与基础支持中的access_token不同) 
    3、如果需要,开发者可以刷新网页授权access_token,避免过期 
    4、通过网页授权access_token和openid获取用户基本信息(支持UnionID机制) 
     
    了解到网页授权的这些知识,下面就开始去实现吧~
     
    开始的准备工作:在接口配置中,设置对应的回调域名,地址:“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项
    由于我的是个人,因此使用测试账号的配置:

    配置好了,就可以进行开发了,首先来看一下具体的流程:

    其实很多功能点,前面已经实现过,只用改一下调用地址和参数即可。

     首先,调用的定义链接:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

    链接中需要使用urlEncode对链接进行处理,可以在工具类中添加一个转码方法:

     1     /**
     2      * 对URL地址进行EnCode处理
     3      * @param url
     4      * @return
     5      */
     6     public static String urlEnCode(String url)
     7     {
     8         String enCodedUrl = "";
     9 
    10         try
    11         {
    12             enCodedUrl = URLEncoder.encode(url, "utf-8");
    13         }
    14         catch (UnsupportedEncodingException e)
    15         {
    16             // TODO Auto-generated catch block
    17             e.printStackTrace();
    18             System.out.println("转码失败!");
    19         }
    20 
    21         return enCodedUrl;
    22     }
    View Code

    另外将其他参数补充完整,可以得到一个访问链接。 

    在这里,可以结合之前学的菜单的处理,可以定义一个菜单进行专门的授权验证,这里需要改造上一节学到的点,具体如下:

     1     /**
     2      * 定义菜单属性
     3      * @return
     4      */
     5     private Menu getMenu()
     6     {
     7         Menu menu = new Menu();
     8 
     9         // 建3个导航菜单
    10         LevelMenu tLevelMenuOne = new LevelMenu();
    11         tLevelMenuOne.setName("Damon");
    12         LevelMenu tLevelMenuTwo = new LevelMenu();
    13         tLevelMenuTwo.setName("Panou");
    14         LevelMenu tLevelMenuThree = new LevelMenu();
    15         tLevelMenuThree.setName("Papaw");
    16 
    17         // 第一个导航菜单的子菜单
    18         SubMenuButton tSubMenuButton_oneone = new SubMenuButton();
    19         tSubMenuButton_oneone.setType(SysCon.WECHAT_MENU_TYPE_VIEW);
    20         tSubMenuButton_oneone.setName("网页授权");
    21         tSubMenuButton_oneone.setKey("11");
    22         tSubMenuButton_oneone.setUrl(getAuthorUrl());
    23 
    24         SubMenuButton tSubMenuButton_onetwo = new SubMenuButton();
    25         tSubMenuButton_onetwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
    26         tSubMenuButton_onetwo.setName("swimming");
    27         tSubMenuButton_onetwo.setKey("12");
    28 
    29         // 加入导航菜单
    30         tLevelMenuOne.setSub_button(new SubMenuButton[]
    31         { tSubMenuButton_oneone, tSubMenuButton_onetwo });
    32 
    33         // 第二 个导航菜单的子菜单
    34         SubMenuButton tSubMenuButton_twoone = new SubMenuButton();
    35         tSubMenuButton_twoone.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
    36         tSubMenuButton_twoone.setName("watching TV");
    37         tSubMenuButton_twoone.setKey("21");
    38 
    39         SubMenuButton tSubMenuButton_twotwo = new SubMenuButton();
    40         tSubMenuButton_twotwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
    41         tSubMenuButton_twotwo.setName("play games");
    42         tSubMenuButton_twotwo.setKey("22");
    43 
    44         SubMenuButton tSubMenuButton_twothree = new SubMenuButton();
    45         tSubMenuButton_twothree.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
    46         tSubMenuButton_twothree.setName("shopping");
    47         tSubMenuButton_twothree.setKey("23");
    48 
    49         // 加入导航菜单
    50         tLevelMenuTwo.setSub_button(new SubMenuButton[]
    51         { tSubMenuButton_twoone, tSubMenuButton_twotwo, tSubMenuButton_twothree });
    52 
    53         // 第三个导航菜单的子菜单
    54         SubMenuButton tSubMenuButton_threeone = new SubMenuButton();
    55         tSubMenuButton_threeone.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
    56         tSubMenuButton_threeone.setName("cring");
    57         tSubMenuButton_threeone.setKey("31");
    58 
    59         SubMenuButton tSubMenuButton_threetwo = new SubMenuButton();
    60         tSubMenuButton_threetwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK);
    61         tSubMenuButton_threetwo.setName("laughing");
    62         tSubMenuButton_threetwo.setKey("32");
    63 
    64         // 加入导航菜单
    65         tLevelMenuThree.setSub_button(new SubMenuButton[]
    66         { tSubMenuButton_threeone, tSubMenuButton_threetwo });
    67 
    68         menu.setButton(new MenuButton[]
    69         { tLevelMenuOne, tLevelMenuTwo, tLevelMenuThree });
    70 
    71         return menu;
    72 
    73     }
    74 
    75     /**
    76      * 获取微信网页授权页面链接
    77      * @return
    78      */
    79     private String getAuthorUrl()
    80     {
    81         String uri = "http://damonhouse.iok.la/Servlet/WeChatAuthorService";
    82 
    83         uri = WeChatUtil.urlEnCode(uri);
    84 
    85         String authorUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
    86 
    87         authorUrl = authorUrl.replace("APPID", "appid").replace("REDIRECT_URI", uri).replace("SCOPE", "snsapi_userinfo");
    88 
    89         return authorUrl;
    90     }
    View Code

    先看一下具体效果:

    点击会弹出一个授权的页面(由于我已经授权过,所以这里会自动登录)

    这个时候后台还没有对应的处理,我们需要进行返回页面的处理,这里定义对应的service类,在doGet方法中进行处理:

     1 /**
     2  * 微信授权接口类
     3  * @author Damon
     4  */
     5 public class WeChatAuthorService extends HttpServlet
     6 {
     7 
     8     @Override
     9     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
    10     {
    11         // TODO Auto-generated method stub
    12         System.out.println("授权成功,进行返回处理!");
    13         req.setCharacterEncoding("utf-8");
    14         resp.setCharacterEncoding("utf-8");
    15 
    16         String code = req.getParameter("code");
    17 
    18         String state = req.getParameter("state");
    19 
    20         System.out.println("code :" + code + " and stat :" + state);
    21 
    22         // 业务处理,获取授权用户信息
    23         WeChatAuthorBL tWeChatAuthorBL = new WeChatAuthorBL();
    24         AuthorUserInfo tAuthorUserInfo = tWeChatAuthorBL.getAuthorData(code, state);
    25 
    26         req.setAttribute("nickname", tAuthorUserInfo.getNickname());
    27         // 获取信息成功,回写成功页面
    28         req.getRequestDispatcher("../wechat/authorsucc.jsp").forward(req, resp);
    29 
    30     }
    31 
    32     @Override
    33     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
    34     {
    35         // TODO Auto-generated method stub
    36         super.doPost(req, resp);
    37     }
    38 
    39 
    40 }
    View Code

     可以从授权中获取到 code 和state(可自定义用与此处校验), 然后就是通过code来进行获取授权的用户信息:

    从前面分析可知,需要先获取授权的acces_token,然后才能获取到授权的用户信息,那么结合前面2节内容,先定义2个实体类:

    1、用户授权Token类

     1 /**
     2  * 用户授权Token
     3  * @author Damon
     4  */
     5 public class AuthorToken
     6 {
     7     // 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
     8     private String access_token = "";
     9 
    10     // access_token接口调用凭证超时时间,单位(秒)
    11     private int expires_in = 0;
    12 
    13     // 用户刷新access_token ="";
    14     private String refresh_token = "";
    15 
    16     // 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
    17     private String openid = "";
    18 
    19     // 用户授权的作用域,使用逗号(,)分隔
    20     private String scope = "";
    21 
    22     public String getAccess_token()
    23     {
    24         return access_token;
    25     }
    26 
    27     public void setAccess_token(String access_token)
    28     {
    29         this.access_token = access_token;
    30     }
    31 
    32     public int getExpires_in()
    33     {
    34         return expires_in;
    35     }
    36 
    37     public void setExpires_in(int expires_in)
    38     {
    39         this.expires_in = expires_in;
    40     }
    41 
    42     public String getRefresh_token()
    43     {
    44         return refresh_token;
    45     }
    46 
    47     public void setRefresh_token(String refresh_token)
    48     {
    49         this.refresh_token = refresh_token;
    50     }
    51 
    52     public String getOpenid()
    53     {
    54         return openid;
    55     }
    56 
    57     public void setOpenid(String openid)
    58     {
    59         this.openid = openid;
    60     }
    61 
    62     public String getScope()
    63     {
    64         return scope;
    65     }
    66 
    67     public void setScope(String scope)
    68     {
    69         this.scope = scope;
    70     }
    71 
    72 }
    View Code

    2、授权用户信息类

      1 /**
      2  * 通过网页授权获取的用户信息
      3  * @author Damon
      4  */
      5 public class AuthorUserInfo
      6 {
      7     // 用户的唯一标识
      8     private String openid = "";
      9 
     10     // 用户昵称
     11     private String nickname = "";
     12 
     13     // 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
     14     private String sex = "";
     15 
     16     // 用户个人资料填写的省份
     17     private String province = "";
     18 
     19     // 普通用户个人资料填写的城市
     20     private String city = "";
     21 
     22     // 国家,如中国为CN
     23     private String country = "";
     24 
     25     // 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
     26     private String headimgurl = "";
     27 
     28     // 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
     29     private List<String> privilege = new ArrayList<String>();
     30 
     31     // 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
     32     private String unionid = "";
     33 
     34     public String getOpenid()
     35     {
     36         return openid;
     37     }
     38 
     39     public void setOpenid(String openid)
     40     {
     41         this.openid = openid;
     42     }
     43 
     44     public String getNickname()
     45     {
     46         return nickname;
     47     }
     48 
     49     public void setNickname(String nickname)
     50     {
     51         this.nickname = nickname;
     52     }
     53 
     54     public String getSex()
     55     {
     56         return sex;
     57     }
     58 
     59     public void setSex(String sex)
     60     {
     61         this.sex = sex;
     62     }
     63 
     64     public String getProvince()
     65     {
     66         return province;
     67     }
     68 
     69     public void setProvince(String province)
     70     {
     71         this.province = province;
     72     }
     73 
     74     public String getCity()
     75     {
     76         return city;
     77     }
     78 
     79     public void setCity(String city)
     80     {
     81         this.city = city;
     82     }
     83 
     84     public String getCountry()
     85     {
     86         return country;
     87     }
     88 
     89     public void setCountry(String country)
     90     {
     91         this.country = country;
     92     }
     93 
     94     public String getHeadimgurl()
     95     {
     96         return headimgurl;
     97     }
     98 
     99     public void setHeadimgurl(String headimgurl)
    100     {
    101         this.headimgurl = headimgurl;
    102     }
    103 
    104     public List<String> getPrivilege()
    105     {
    106         return privilege;
    107     }
    108 
    109     public void setPrivilege(List<String> privilege)
    110     {
    111         this.privilege = privilege;
    112     }
    113 
    114     public String getUnionid()
    115     {
    116         return unionid;
    117     }
    118 
    119     public void setUnionid(String unionid)
    120     {
    121         this.unionid = unionid;
    122     }
    123 
    124 }
    View Code

    下一步,就是通过调用接口来实现我们的功能了~

      1     /**
      2      * 获取授权用户
      3      * @param code
      4      * @param state
      5      * @return
      6      */
      7     public AuthorUserInfo getAuthorData(String code, String state)
      8     {
      9 
     10         // 1、通过code获取授权的authortoken
     11         AuthorToken tAuthorToken = getAuthorToken("appid", "appsecret", code);
     12 
     13         // 2、通过获取的 access_token和 openid 获取用户信息
     14         AuthorUserInfo tAuthorUserInfo = getAuthorUserInfo(tAuthorToken.getAccess_token(), tAuthorToken.getOpenid());
     15 
     16         return tAuthorUserInfo;
     17     }
     18 
     19 
     20     /**
     21      * 获取授权的access_token
     22      * @param appid
     23      * @param appsceret
     24      * @param code
     25      * @return
     26      */
     27     private AuthorToken getAuthorToken(String appid, String appsceret, String code)
     28     {
     29 
     30         String path = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code ";
     31 
     32         path = path.replace("APPID", appid).replace("SECRET", appsceret).replace("CODE", code);
     33 
     34         AuthorToken tAuthorToken = new AuthorToken();
     35 
     36         try
     37         {
     38             String strResp = WeChatUtil.doHttpsGet(path, "");
     39 
     40             System.out.println(strResp);
     41 
     42             // 解析获取的token信息
     43             Map<String, Object> tMap = WeChatUtil.jsonToMap(strResp);
     44 
     45             System.out.println(tMap.toString());
     46 
     47             // 封装 authortoken
     48 
     49             tAuthorToken.setAccess_token((String) tMap.get("access_token"));
     50             tAuthorToken.setExpires_in(Integer.parseInt((String) tMap.get("expires_in")));
     51             tAuthorToken.setOpenid((String) tMap.get("openid"));
     52             tAuthorToken.setScope((String) tMap.get("scope"));
     53             tAuthorToken.setRefresh_token((String) tMap.get("refresh_token"));
     54 
     55         }
     56         catch (HttpException e)
     57         {
     58             // TODO Auto-generated catch block
     59             e.printStackTrace();
     60         }
     61         catch (IOException e)
     62         {
     63             // TODO Auto-generated catch block
     64             e.printStackTrace();
     65         }
     66 
     67         return tAuthorToken;
     68     }
     69 
     70 
     71     /**
     72      * 通过授权的access_token及用户的openid来拉取用户信息
     73      * @param access_token
     74      * @param openid
     75      * @return
     76      */
     77     private AuthorUserInfo getAuthorUserInfo(String access_token, String openid)
     78     {
     79         String path = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
     80 
     81         path = path.replace("ACCESS_TOKEN", access_token).replace("OPENID", openid);
     82 
     83         AuthorUserInfo tAuthorUserInfo = new AuthorUserInfo();
     84 
     85         try
     86         {
     87             String strResp = WeChatUtil.doHttpsGet(path, "");
     88 
     89             System.out.println(strResp);
     90 
     91             // 解析获取的token信息
     92             Map<String, Object> tMap = WeChatUtil.jsonToMap(strResp);
     93 
     94             System.out.println(tMap.toString());
     95 
     96             // 封装 authortoken
     97             tAuthorUserInfo.setOpenid((String) tMap.get("openid"));
     98             tAuthorUserInfo.setNickname((String) tMap.get("nickname"));
     99             tAuthorUserInfo.setSex((String) tMap.get("sex"));
    100             tAuthorUserInfo.setCountry((String) tMap.get("country"));
    101             tAuthorUserInfo.setProvince((String) tMap.get("province"));
    102             tAuthorUserInfo.setCity((String) tMap.get("city"));
    103             tAuthorUserInfo.setHeadimgurl((String) tMap.get("headimgurl"));
    104             tAuthorUserInfo.setPrivilege((List<String>) tMap.get("privilege"));
    105             tAuthorUserInfo.setUnionid((String) tMap.get("unionid"));
    106         }
    107         catch (HttpException e)
    108         {
    109             // TODO Auto-generated catch block
    110             e.printStackTrace();
    111         }
    112         catch (IOException e)
    113         {
    114             // TODO Auto-generated catch block
    115             e.printStackTrace();
    116         }
    117 
    118         return tAuthorUserInfo;
    119     }
    View Code

    这些搞定,我们就已经获取到了用户的信息了。 最后我们来给用户一个好的界面体验~

    这里新增一个页面,显示获取到的用户昵称:

     1 <%@ page language="java" contentType="text/html; charset=GBK"
     2     pageEncoding="GBK"%>
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     4 <html>
     5 <head>
     6 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
     7 <title>damon's house</title>
     8 </head>
     9 <body>
    10 <%
    11 String nickname=request.getAttribute("nickname").toString();
    12 %>
    13 <table><tr><%=nickname %> 您好,感谢授权Damon的奇趣小屋!</tr></table>
    14 </body>
    15 </html>
    View Code

    来看一下效果吧~

    微信网页授权,获取用户信息就到这啦~  

     
  • 相关阅读:
    读《弗兰肯斯坦》:如何对待世界的恶意?
    ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'PASSWORD
    Exception in thread "main" java.awt.AWTError: Can't connect to X11 window server using ':0'.在wanyland模式下面启动allure服务报错了
    python 调用so动态库函数时传char参数
    configparser库会自动修改成小写的问题
    python base64 文件
    "unable to execute 'gcc': No such file or directory error: command 'gcc' failed with exit status 1"今天在loogarch安转oss2报错了~
    No module named 'setuptools_rust' 安装oss2报错
    yum 添加完源后更新 sudo yum makecache fast
    处理机调度与死锁
  • 原文地址:https://www.cnblogs.com/cooldamon/p/7219400.html
Copyright © 2020-2023  润新知