文章目录

  • 1.OAuth2.0
  • 2. 微信扫描登录的准备
  • 3. 微信登录
    • 3.1 在service-ucenter模块配置文件 微信id,密钥和域名地址
    • 3.2创建读取配置文件的类
    • 3.3 生成微信扫描二维码
      • 3.3.1 获取微信二维码
      • 3.3.2 微信扫描之后的步骤
      • 3.3.3 微信登录功能完善

1.OAuth2.0

OAuth2.0是针对特定问题的一种解决方案,主要解决两个问题 1. 开放系统间授权 2. 分布式访问问题

2. 微信扫描登录的准备

  1. 注册开发中资质:支持企业类型,注册之后提供微信id和微信密钥
  2. 申请网站应用名称
  3. 需要域名地址(尚硅谷给我们准备好了)

3. 微信登录

3.1 在service-ucenter模块配置文件 微信id,密钥和域名地址

# 微信开放平台 appid
wx.open.app_id=wxed9954c01bb89b47
# 微信开放平台 appsecret
wx.open.app_secret=a7482517235173ddb4083788de60b90e
# 微信开放平台 重定向url
wx.open.redirect_url=http://localhost:8160/api/educenter/wx/callback

3.2创建读取配置文件的类

在service-enter下创建一个utils包,该包下创建一个ConstantWxUtils 用于微信登录相关的配置

@Component
public class ConstantWxUtils  implements InitializingBean {@Value("${wx.open.app_id}")private String appId;@Value("${wx.open.app_secret}")private String appSecret;@Value("${wx.open.redirect_url}")private String redirectUrl;public static String WX_OPEN_APP_ID;public static String WX_OPEN_APP_SECRET;public static String WX_OPEN_REDIRECT_URL;@Overridepublic void afterPropertiesSet() throws Exception {WX_OPEN_APP_ID = appId;WX_OPEN_APP_SECRET = appSecret;WX_OPEN_REDIRECT_URL = redirectUrl;}
}

3.3 生成微信扫描二维码

3.3.1 获取微信二维码

直接请求微信提供固定的地址,向地址后面拼接参数
controller

@CrossOrigin
@Controller
@RequestMapping("/api/educenter/wx")
public class WxApiController {//生成微信登录二维码@GetMapping("/login")public String getCode(){// 微信开放平台授权baseUrl  %s表示?占位符String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +"?appid=%s" +"&redirect_uri=%s" +"&response_type=code" +"&scope=snsapi_login"+"&state=%s" +"#wechat_redirect";//对redirect_url进行URLEncode编码String redirectUrl= ConstantWxUtils.WX_OPEN_REDIRECT_URL;String encode=null;try {encode= URLEncoder.encode(redirectUrl, "utf-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}//设置%s的值String s = String.format(baseUrl,ConstantWxUtils.WX_OPEN_APP_ID,encode,"atguigu");//重定向请求微信地址return "redirect:"+s;}
}

微信扫描后的地址为:http://localhost:8150/api/educenter/wx/callback
我们需要在域名地址里面写程序,做出处理1. 把本地端口改为8160 2. 回调接口地址和域名跳转地址写成一样

3.3.2 微信扫描之后的步骤

  1. 扫描之后,执行本地的callback方法,在fallback获取两个值,在跳转的时候传递过来
  • state:原样传递
  • code:类似手机验证码,随机唯一值
  1. 拿着第一步的获取到的code值,请求微信提供的固定地址,获取到两个值
  • access_token:访问凭证
  • openid:每个微信唯一标识
  1. 拿着第二步获取的两个值access_toekn和openid,在去请求微信提供的一个固定地址,最终获取到微信扫描人的信息

用到的技术点:httpClient,Json转换工具(fast json 、gson)
代码实现
创建一个Http请求的工具类

public class HttpClientUtils {public static final int connTimeout=10000;public static final int readTimeout=10000;public static final String charset="UTF-8";private static HttpClient client = null;static {PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();cm.setMaxTotal(128);cm.setDefaultMaxPerRoute(128);client = HttpClients.custom().setConnectionManager(cm).build();}public static String postParameters(String url, String parameterStr) throws ConnectTimeoutException, SocketTimeoutException, Exception{return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);}public static String postParameters(String url, String parameterStr,String charset, Integer connTimeout, Integer readTimeout) throws ConnectTimeoutException, SocketTimeoutException, Exception{return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);}public static String postParameters(String url, Map<String, String> params) throws ConnectTimeoutException,SocketTimeoutException, Exception {return postForm(url, params, null, connTimeout, readTimeout);}public static String postParameters(String url, Map<String, String> params, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,SocketTimeoutException, Exception {return postForm(url, params, null, connTimeout, readTimeout);}public static String get(String url) throws Exception {return get(url, charset, null, null);}public static String get(String url, String charset) throws Exception {return get(url, charset, connTimeout, readTimeout);}/*** 发送一个 Post 请求, 使用指定的字符集编码.** @param url* @param body RequestBody* @param mimeType 例如 application/xml "application/x-www-form-urlencoded" a=1&b=2&c=3* @param charset 编码* @param connTimeout 建立链接超时时间,毫秒.* @param readTimeout 响应超时时间,毫秒.* @return ResponseBody, 使用指定的字符集编码.* @throws ConnectTimeoutException 建立链接超时异常* @throws SocketTimeoutException  响应超时* @throws Exception*/public static String post(String url, String body, String mimeType,String charset, Integer connTimeout, Integer readTimeout)throws ConnectTimeoutException, SocketTimeoutException, Exception {HttpClient client = null;HttpPost post = new HttpPost(url);String result = "";try {if (StringUtils.isNotBlank(body)) {HttpEntity entity = new StringEntity(body, ContentType.create(mimeType, charset));post.setEntity(entity);}// 设置参数RequestConfig.Builder customReqConf = RequestConfig.custom();if (connTimeout != null) {customReqConf.setConnectTimeout(connTimeout);}if (readTimeout != null) {customReqConf.setSocketTimeout(readTimeout);}post.setConfig(customReqConf.build());HttpResponse res;if (url.startsWith("https")) {// 执行 Https 请求.client = createSSLInsecureClient();res = client.execute(post);} else {// 执行 Http 请求.client = HttpClientUtils.client;res = client.execute(post);}result = IOUtils.toString(res.getEntity().getContent(), charset);} finally {post.releaseConnection();if (url.startsWith("https") && client != null&& client instanceof CloseableHttpClient) {((CloseableHttpClient) client).close();}}return result;}/*** 提交form表单** @param url* @param params* @param connTimeout* @param readTimeout* @return* @throws ConnectTimeoutException* @throws SocketTimeoutException* @throws Exception*/public static String postForm(String url, Map<String, String> params, Map<String, String> headers, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,SocketTimeoutException, Exception {HttpClient client = null;HttpPost post = new HttpPost(url);try {if (params != null && !params.isEmpty()) {List<NameValuePair> formParams = new ArrayList<NameValuePair>();Set<Entry<String, String>> entrySet = params.entrySet();for (Entry<String, String> entry : entrySet) {formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);post.setEntity(entity);}if (headers != null && !headers.isEmpty()) {for (Entry<String, String> entry : headers.entrySet()) {post.addHeader(entry.getKey(), entry.getValue());}}// 设置参数Builder customReqConf = RequestConfig.custom();if (connTimeout != null) {customReqConf.setConnectTimeout(connTimeout);}if (readTimeout != null) {customReqConf.setSocketTimeout(readTimeout);}post.setConfig(customReqConf.build());HttpResponse res = null;if (url.startsWith("https")) {// 执行 Https 请求.client = createSSLInsecureClient();res = client.execute(post);} else {// 执行 Http 请求.client = HttpClientUtils.client;res = client.execute(post);}return IOUtils.toString(res.getEntity().getContent(), "UTF-8");} finally {post.releaseConnection();if (url.startsWith("https") && client != null&& client instanceof CloseableHttpClient) {((CloseableHttpClient) client).close();}}}/*** 发送一个 GET 请求** @param url* @param charset* @param connTimeout  建立链接超时时间,毫秒.* @param readTimeout  响应超时时间,毫秒.* @return* @throws ConnectTimeoutException   建立链接超时* @throws SocketTimeoutException   响应超时* @throws Exception*/public static String get(String url, String charset, Integer connTimeout,Integer readTimeout)throws ConnectTimeoutException,SocketTimeoutException, Exception {HttpClient client = null;HttpGet get = new HttpGet(url);String result = "";try {// 设置参数Builder customReqConf = RequestConfig.custom();if (connTimeout != null) {customReqConf.setConnectTimeout(connTimeout);}if (readTimeout != null) {customReqConf.setSocketTimeout(readTimeout);}get.setConfig(customReqConf.build());HttpResponse res = null;if (url.startsWith("https")) {// 执行 Https 请求.client = createSSLInsecureClient();res = client.execute(get);} else {// 执行 Http 请求.client = HttpClientUtils.client;res = client.execute(get);}result = IOUtils.toString(res.getEntity().getContent(), charset);} finally {get.releaseConnection();if (url.startsWith("https") && client != null && client instanceof CloseableHttpClient) {((CloseableHttpClient) client).close();}}return result;}/*** 从 response 里获取 charset** @param ressponse* @return*/@SuppressWarnings("unused")private static String getCharsetFromResponse(HttpResponse ressponse) {// Content-Type:text/html; charset=GBKif (ressponse.getEntity() != null  && ressponse.getEntity().getContentType() != null && ressponse.getEntity().getContentType().getValue() != null) {String contentType = ressponse.getEntity().getContentType().getValue();if (contentType.contains("charset=")) {return contentType.substring(contentType.indexOf("charset=") + 8);}}return null;}/*** 创建 SSL连接* @return* @throws GeneralSecurityException*/private static CloseableHttpClient createSSLInsecureClient() throws GeneralSecurityException {try {SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {public boolean isTrusted(X509Certificate[] chain,String authType) throws CertificateException {return true;}}).build();SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {@Overridepublic boolean verify(String arg0, SSLSession arg1) {return true;}@Overridepublic void verify(String host, SSLSocket ssl)throws IOException {}@Overridepublic void verify(String host, X509Certificate cert)throws SSLException {}@Overridepublic void verify(String host, String[] cns,String[] subjectAlts) throws SSLException {}});return HttpClients.custom().setSSLSocketFactory(sslsf).build();} catch (GeneralSecurityException e) {throw e;}}}

微信登录接口的实现

@CrossOrigin
@Controller
@RequestMapping("/api/educenter/wx")
public class WxApiController {@Autowiredprivate UcenterMemberService memberService;//获取扫描信息,添加数据@GetMapping("callback")public String callback(String code,String state) {try{System.out.println("code" + code);System.out.println("state" + state);//1. 向认证服务器发送请求换取access_tokenString baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +"?appid=%s" +"&secret=%s" +"&code=%s" +"&grant_type=authorization_code";String accessTokenUrl = String.format(baseAccessTokenUrl,ConstantWxUtils.WX_OPEN_APP_ID,ConstantWxUtils.WX_OPEN_APP_SECRET,code);//2.请求这个拼接好的地址,得到两个返回的值 access——token和openid//使用HttpClient发送请求得到返回结果String s = HttpClientUtils.get(accessTokenUrl);System.out.println(s);//从字符串s中获取出两个值 openid access_token//把字符串转换成map集合,根据map里面的key获取对应的值//使用json转换工具 gsonGson gson = new Gson();HashMap hashMap = gson.fromJson(s, HashMap.class);String openid = (String)hashMap.get("openid");String access_token =(String) hashMap.get("access_token");//把扫码人信息添加到数据库//根据openid判断是否存在相同微信的信息UcenterMember member= memberService.getOpenIdMember(openid);if(member==null)//member为空,表示没有相同微信的数据 进行添加{//3.拿着=access_token和openId在去请求微信提供的固定地址获取扫码人的信息//访问微信的资源服务器,获取用户信息String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +"?access_token=%s" +"&openid=%s";//拼接两个参数String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);//发送请求String userInfo = HttpClientUtils.get(userInfoUrl);System.out.println(userInfo);HashMap userMap = gson.fromJson(userInfo, HashMap.class);String nickname =(String) userMap.get("nickname");String headImgurl =(String) userMap.get("headimgurl");member=new UcenterMember();member.setOpenid(openid);member.setNickname(nickname);member.setAvatar(headImgurl);memberService.save(member);}}catch (Exception e){throw new GuliException(20001,"登录失败");}finally {return "redirect:http://localhost:3000";}}

service判断openid是否存在

 //根据openid判断是否存在@Overridepublic UcenterMember getOpenIdMember(String openid) {QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();wrapper.eq("openid",openid);UcenterMember member = baseMapper.selectOne(wrapper);return member;}

3.3.3 微信登录功能完善

之前登录之后,在首页面从cookie获取数据进行显示,现在也可以按照这种方式,把扫描之后的信息放在cookie里面,跳到首页面进行显示,但cookie无法实现跨域访问
最终解决方案:根据微信信息实验jwt,生成字符串,把token字符串通过路径传递到首页面

在layout文件下的default.vue中加入路由地址获取token,调用用户的信息,

尚硅谷在线教育十二:微信登录相关推荐

  1. 尚硅谷在线教育十四:微信支付

    文章目录 1. 前期准备工作 1.1 创建订单相关的表 2.2 创建service_order模块 2. 微信支付后端相关的接口 2.1 生成订单的接口 2.2 根据订单id查询订单信息 2.3 微信 ...

  2. 尚硅谷在线教育十:首页数据显示

    文章目录 1. 首页数据banner显示(后端) 1.1 在service创建子模块service_cms 1.2 创建配置文件 1.3 创建数据库表.使用表生成代码生成器 1.3.1数据库的SQL语 ...

  3. 尚硅谷在线教育十一:登录注册业务

    文章目录 1. 用户登录业务介绍 1.1 单一服务器模式登录 1.2 单点登录 1.3 单点登录的常用三种方式 1.3.1. session广播机制实现 1.3.2 使用cookie+redis实现 ...

  4. 尚硅谷在线教育五:尚硅谷在线教育讲师管理开发

    文章目录 1. 前端登录功能的地址改变 1.1. 修改配置文件的请求地址 2.2登录调用的两个方法 2.2.1编写login和info接口 3 最终测试以及出现的问题 3.1跨域问题 3.2 跨域解决 ...

  5. 尚硅谷在线教育项目的坑

    尚硅谷 在线教育总结 8/28 nginx启动不了 安装路径不能有中文 vscode 修改的代码必须C+S 9/4 正常启动前后端项目还得启动nginx Chrome(谷歌)浏览器跨域请求被阻止,CO ...

  6. 尚硅谷在线教育九:尚硅谷在线教育NUXT搭建前台环境以及相关页面的编写

    文章目录 1.服务端渲染技术NUXT 1.1什么是服务端渲染 1.2什么是NUXT 2.NUXT环境初始化 2.1下载压缩包 2.2解压 2.3安装ESLint 2.4修改package.json 2 ...

  7. 尚硅谷在线教育一:尚硅谷在线教育相关的基本搭建配置以及讲师管理模块

    文章目录 1.项目的总体说明 1.1项目的功能模块说明 1.2项目设计的技术 2创建一个名为guli的springboot的父项目 3. 在guli的项目下创建一个子模块common用于公共使用的模块 ...

  8. 尚硅谷在线教育视频点播

    文章目录 1. 开通阿里云视频点播服务 2.阿里云点播SDK实现 2.1上传视频到阿里云视频点播服务 2.2整合阿里云上传视频的接口 3. 课程信息的完善(为每个课程的小节添加视频) 3.1 添加上传 ...

  9. 尚硅谷在线教育四:尚硅谷在线教育前端的知识

    文章目录 1.axios 1.1 axios简介 1.2使用前景 1.3axios的使用 1.3.1创建HTML文件,引入包含vue和axios的js文件 1.3.2编写axios代码 2. node ...

最新文章

  1. 阿里软件测试工程师手把手教学——自动化测试报告太丑,怎么办?
  2. 很好的Markdown开源库
  3. python经典算法小程序-Python爬虫系列之微信小程序逆向某优选爬虫签名算法!厉害...
  4. GPS服务端解析程序编写日记之--vs2010中多种语言开发及调试的若干注意事项
  5. 《机器学习实战》第十三章 PCA
  6. Sass 基础(三)
  7. 二叉树的应用- 找出倚天屠龙记小说里所有的成语
  8. JTAG各类接口针脚定义、含义以及SWD接线方式
  9. C++利用前序序列和中序序列构建二叉树
  10. 三门问题的扩展用c++模拟
  11. 写给刚接触Auto CAD新人的建议——第三期
  12. php 报警声,php 报警 [NOTICE] fpm_children_bury()
  13. 搞联欢会,你知道什么是音乐吗?(二)
  14. GravitybCamp-链上云计算应用技术分享会
  15. 工业机器人日常维护保养要点总结
  16. python中pack函数_关于pack()函数的文章推荐10篇 - pack
  17. PHP仿百度网盘文件分享dzzoffice网盘系统源码
  18. 如何读关于设计模式的那几本书
  19. 节能降耗——搭建绿色数据中心能耗管控系统
  20. vue拖拽组件插件 vue-draggable-resizable-gorkys

热门文章

  1. Storm - Trident
  2. Robocode介绍
  3. 【华为OD机试真题 JS】用连续自然数之和来表达整数
  4. xdl Java_JAVA和C++区别
  5. 百度周景博:POI知识图谱的构建及应用
  6. 幼儿园教师怎么教计算机知识,幼儿园教师的常识教案大全
  7. iOS编程——Swift实现常见的递归算法1
  8. 磁盘分析软件(C盘爆满精确清理必备)---SpaceSniffer
  9. 非静压模型NHWAVE学习(7)——波浪变形模拟算例学习(Wave transformation over an elliptical shoal)
  10. QT+MQTT 使用MQTT官方库