SSM框架的Web项目实现微信登陆

1 篇文章 0 订阅

最早在2007年时Open Authorization提出了OAuth1.0版,在推出五年后,很多开发者们都觉得OAuth1.0开发过程有点复杂,于是就在OAuth1.0基础之上进行改造就有了后来的OAuth2.0。两者的区别在于,OAuth2.0变得更加简单易用,第二个取消了中间的加密过程同时也保留了OAuth1.0中的安全特性。这就是OAuth2.0的基本概念。(相比于OAuth1.0更加简单易用,取消的中间的加密过程且保留了原1.0的安全特性)
时下比较流行的第三方登录,不管是微信登录还是QQ登录,它们采用的标准都是采用OAuth2.0的协议标准。
接下来看一下,OAuth2.0在微信登录过程当中,它是怎么来进行作用的

在这里插入图片描述
如果在网页中,用户并不想使用普通的流程去注册登陆,而是用微信登陆的话,那么在登陆页面就会提供一个用于微信登陆的链接,当用户点击微信登陆链接的时候,网页会向微信开发平台发送请求,微信开发平台收到请求之后,会生成一个二维码供用户查看,用户进行微信扫码之后,也就是扫码登陆,会拿到被授权的临时票据(Code),这时拿着票据Code以及在单击微信注册登陆的shi’h获取到的appid及appsecret一共三个参数(Code,appid,appsecret).拿着这三个参数去换取一个时间较长的票据,这个票据被称为access_token,微信中access_token被设置为2个小时的有效期,这个时候我们就可以通过access_token获取用户相应微信用户信息.
步骤如下:
1.用户访问项目(网页登陆页面的微信登陆图标),点击微信登录链接。(调用微信登陆的控制层)
2.在从后台跳转到微信登录页时(携带appid,回调地址),展示给用户登录二维码
3.微信用户扫码进行确认授权,微信平台跳转至回调地址(携带临时票据Code)
4.后台接收到请求,根据临时票据appid和appsecret获取access_token。
5. 项目再根据access_token访问微信登录平台获取用户信息,进行登录
问题:之所以要通过临时票据来得到access_token而不是直接获取access_token,是为了保证数据的更加安全,也为了保证access_token不被泄露。
1.接入条件
1.注册微信开发者平台账号
2.拥有一个已过审核的网站应用
实现方式

  1. 浏览器访问 https://open.weixin.qq.com/
  2. 找到网站应用开发点击下方的蓝色链接进入
  3. 点击创建应用
  4. 没有账号就进行注册(审核过后就会拥有(appid和AppSecret))
  5. 邮箱进行激活注册,然后填写相关企业信息
  6. 通过注册的邮箱账号进行登陆,然后按照第三步骤点击创建应用
    填写相关的信息,提交审核,审核在7个工作日内完成。当完成之后我们即可在项目中编写相关的API接口代码:
    在这里插入图片描述
    应用官网其实就是你的项目地址,授权回调域也是你的外网访问地址.
    注意:授权回调域前缀不能有http,后缀不能带"/"。
参数是否必须说明
appid应用唯一标识(网站应用审核通过后,会获取到appid和appsecret)
redirect_uri回调地址,即当用户扫描二维码授权通过后,微信平台要请求网站的URL由它指定。注:需要urlEncode对链接进行处理
response_type填写code (值固定是code)
scope应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login。
state用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验。

**

2. 通过code获取access_token

  1. 获取access_token
    https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
  2. 参数说明:
    在这里插入图片描述
    **
    如果获取正确那么返回的JSON字符串如下:

{
“access_token”:“ACCESS_TOKEN”,
“expires_in”:7200,
“refresh_token”:“REFRESH_TOKEN”,
“openid”:“OPENID”,
“scope”:“SCOPE”,
“unionid”: “o6_bmasdasdsad6_2sgVt7hMZOPfL”
}

参数说明:
在这里插入图片描述
错误返回案例:

{“errcode”:40030,“errmsg”:“invalid refresh_token”}

本次代码演示在多模块当中进行布局:
因为是与登陆相关的,所以我将其写在了我的认证模块当中,认证模块就是对登陆用户的认证及Token的处理。如下:
在这里插入图片描述
首先在工具类模块中的common目录中导入UrlUtils这个类,然后在认证模块下的controller目录下创建WxLoginController类,这个类就是处理微信登陆的控制层:
1.在这里插入图片描述
在这里插入图片描述

1. UrlUtils类中的内容:

package cn.itrip.common;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 本类提供了对URL所指向的内容的加载操作
 * @author hduser
 *
 */
public class UrlUtils {

	/**
	 * 获取url网址返回的数据内容
	 * @param urlStr
	 * @return
	 */
	public static String loadURL(String urlStr){
		try{  
	        URL url = new URL(urlStr);  
	        HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();	              
	        urlConnection.setRequestMethod("GET");  
		    urlConnection.connect(); 	          
		    InputStream inputStream = urlConnection.getInputStream(); 
		    String responseStr = ConvertToString(inputStream);  
		    return responseStr;
		}catch(IOException e){  
		    e.printStackTrace(); 
		    return null;
		}
	}
	private static String ConvertToString(InputStream inputStream){  
	    InputStreamReader inputStreamReader = new InputStreamReader(inputStream);  
	    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  
	    StringBuilder result = new StringBuilder();  
	    String line = null;  
	    try {  
	        while((line = bufferedReader.readLine()) != null){  
	            result.append(line + "\n");  
	        }  
	    } catch (IOException e) {  
	        e.printStackTrace();  
	    } finally {  
	        try{  
	            inputStreamReader.close();  
	            inputStream.close();  
	            bufferedReader.close();  
	        }catch(IOException e){  
	            e.printStackTrace();  
	        }  
	    }  
	    return result.toString();  
	}  
}

2.认证模块中的代码:

在这里插入图片描述

package cn.itrip.auth.controller.Login;

import cn.itrip.common.UrlUtils;
import com.alibaba.fastjson.JSON;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletResponse;
import java.util.Map;

@Controller
@RequestMapping("/wx/login")
public class WxLoginController {
    //日志对象
    private Logger logger = Logger.getLogger(WxLoginController.class);

    /**
     *
     * @param code             授权的临时票据
     * @param state            用于保持请求和回调的状态,授权请求后原样带回给第三方。
     *                         该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,
     *                         可设置为简单的随机数加session进行校验。
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/callBackWeChat",method= RequestMethod.POST)
    public void callBackWeChat(@RequestParam String code,
                               @RequestParam String state,
                               HttpServletResponse response) throws Exception {
        /**
         * 1.编写请求code
         * 1.1.请求地址
         * appid=应用唯一标识(网站应用审核通过后,会获取到appid和appsecret)
         * secret=应用密钥AppSecret,在微信开放平台提交应用审核通过后获得
         * code=code参数
         * grant_type=填authorization_code
         */
        String accessUrl="https://api.weixin.qq.com/sns/oauth2/access_token" +
                "?appid=wx860bf23c66d93e33" +
                "&secret=9c92026ab4faa4a4f7ac4cf10b2a8a3c" +
                "&code=" + code +
                "&grant_type=authorization_code";
        //1.2通过发送accessUrl请求地址,并得到返回参数,返回的参数是一个json字符串
        String jsonStr = UrlUtils.loadURL(accessUrl);
        //将json字符串转换成Map集合
        Map<String,String> accessMap= JSON.parseObject(jsonStr, Map.class);
        /**
         * 2.通过code——access_token获取json字符串/accessMap集合中的accessToken,
         * 也就是获取集合中的“接口调用凭证”
         */
        String accessToken = accessMap.get("access_token");
        //3.获取授权用户唯一标识
        String openId=accessMap.get("openid");
        logger.info("accessToken的值为:" + accessToken + ",openId的值为:" + openId);
        //重定向网址
        response.sendRedirect("http://www.baidu.com");
    }
}

3. 通过access_token和openid获取当前微信的用户信息

1. 请求地址

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID

2. 参数说明:

参数是否必须说明
access_token接口调用凭证
openid普通用户的标识,对当前开发者帐号唯一(授权用户唯一标识)
lang国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语,默认为zh-CN

3.获取后返回的正确的JSON字符串

{
"openid":"OPENID",
"nickname":"NICKNAME",  #昵称
"sex":1,                 #性别
"province":"PROVINCE",    #省
"city":"CITY",             #市
"country":"COUNTRY",     #国家
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"privilege":[
"PRIVILEGE1",
"PRIVILEGE2"
],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

上述返回的JSON字符串的参数说明:

参数说明
openid普通用户的标识,对当前开发者帐号唯一
nickname普通用户昵称
sex普通用户性别,1为男性,2为女性
province普通用户个人资料填写的省份
city普通用户个人资料填写的城市
country国家,如中国为CN
headimgurl用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
privilege用户特权信息,json数组,如微信沃卡用户为(chinaunicom)
unionid用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的

4. 返回错误的JSON字符串

{ “errcode”:40003,“errmsg”:“invalid openid” }

3. 代码编写

对认证模块itripauth中之前编写的WxLoginController类的callBackWeChat方法进行修改,如下:
找到log4j日志输出语句,也就是:

logger.info(“accessToken的值为:” + accessToken + “,openId的值为:” + openId);

1.在这后面通过请求地址获取登陆的微信用户信息也就是 通过access_tokenopenid获取当前微信的用户信息如下:

/**
  4.通过access_token获取用户信息,
  参考:资源中心 网站应用微信登录功能授权后接口调用获取用户个人信息(UnionID机制)
  4.1 请求URL地址
*/
String userInfoUrl="https://api.weixin.qq.com/sns/userinfo?access_token="
                            + accessToken +
                            "&openid=" + openId;
  1. 发送请求,返回JSON字符串
  2. 获取用户个人信息
String userInfoStr = UrlUtils.loadURL(userInfoUrl);
  1. 获取用户信息中的城市
 Map<String,String> userInfoMap = JSON.parseObject(userInfoStr, Map.class);
        //3.3 获取用户个人信息
        String city = userInfoMap.get("city");//获取用户信息中的城市
  1. 获取用户昵称
 String nickname = userInfoMap.get("nickname");
  1. 日志输出这些用户信息
logger.info("city的值为:" + city + ",nickname的值为:" + nickname);

整块代码如下:

logger.info("accessToken的值为:" + accessToken + ",openId的值为:" + openId);

        //3、通过access_token获取用户信息,参考:资源中心 网站应用微信登录功能授权后接口调用获取用户个人信息(UnionID机制)
        //3.1 请求URL地址
        String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId;
        //3.2 发送请求,返回JSON字符串
        String userInfoStr = UrlUtils.loadURL(userInfoUrl);
        Map<String,String> userInfoMap = JSON.parseObject(userInfoStr, Map.class);
        //3.3 获取用户个人信息
        String city = userInfoMap.get("city"); //获取用户信息中的城市
        String nickname = userInfoMap.get("nickname");
        logger.info("city的值为:" + city + ",nickname的值为:" + nickname);

        response.sendRedirect("http://www.baidu.com");

这个时候我就在linux服务器上启动sunny-ngrok,通过外网域名访问linux服务器,然后将项目打包放在linux服务器上,之打包当前模块测试运行,如下:
注:要放在对应的tomcat容器上,端口要一致:
在这里插入图片描述
启动tomcat之后通过外网域名+项目名访问项目:
在这里插入图片描述
这个时候访问微信登陆页面:
https://open.weixin.qq.com/connect/qrconnect?appid=wx860bf23c66d93e33&redirect_uri=http%3a%2f%2fitripDebug.vipgz1.idcfengye.com%2fitripauth%2fwx%2flogin%2fcallBackWeChat&response_type=code&scope=snsapi_login&state=12512#wechat_redirect

参数说明
appid应用唯一标识(网站应用审核通过后,会获取到appid和appsecret)

在这里插入图片描述

参数说明
redirect_uri回调地址,即当用户扫描二维码授权通过后,微信平台要请求网站的URL由它指定。注:需要urlEncode对链接进行处理。对应项目的Controller处理方法地址,上述的地址进行拆分为: redirect_uri**=http%3a%2f%2fitripDebug.vipgz1.idcfengye.com%2fitripauth%2fwx%2flogin%2fcallBackWeChat
第一个加粗的蓝色字体对应我们上述说的启动了sunny-ngrok后的外网域名,第二个加粗的字体也就是itripauth对应了项目名,第三个加粗的字体wx对应了控制层地址,第四个加粗的地址login也对赢了controller地址,第五个callBackWeChat对应了方法名,也就是对应http://itripdebug.vipgz1.idcfengye.com/itripauth/wx/login/callBackWeChat

如下:
在这里插入图片描述
可以清楚得看到层次分名的方法调用,根据自己的方法地址更改值即可,
这个时候调用微信登陆扫码页面即可看到成功调用方法,项目配了log4j地址就可在配置地址的log4j日志文件中查看输出的日志信息,如下:
在这里插入图片描述
这个时候就说明自己的微信登陆扫码是成功完成了,后续根据项目需要进行数据的存储,如Token,redis这些!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值