本文共 9617 字,大约阅读时间需要 32 分钟。
准备营业执照,1-2个工作日审批、300元
提交审核,7个工作日审批
ngrok的使用
参考文档:
获取access_token时序图
# 微信开放平台 appidwx.open.app_id=你的appid# 微信开放平台 appsecretwx.open.app_secret=你的appsecret# 微信开放平台 重定向urlwx.open.redirect_url=http://你的服务器名称/api/ucenter/wx/callback
@Componentpublic class ConstantWeChatUtils 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; @Override public void afterPropertiesSet() throws Exception { WX_OPEN_APP_ID = appid; WX_OPEN_APP_SECRET = appsecret; WX_OPEN_REDIRECT_URL = redirectUrl; }}
①登录ngrok官网:http://www.ngrok.cc
②注册账号,依据个人情况申请开通隧道。
③填写隧道相关配置④申请成功后下载Ngrok客户端,并启动Ngrok
①访问微信提供的固定的地址,向地址里面拼接参数,二维码就可以生成出来
https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
参数说明
参数 | 是否必须 | 说明 |
---|---|---|
appid | 是 | 应用唯一标识 |
redirect_uri | 是 | 请使用urlEncode对链接进行处理 |
response_type | 是 | 填code |
scope | 是 | 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即 |
state | 是 | 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验 |
②创建生成二维码的方法(Controller)
@Controller@RequestMapping("/api/ucenter/wx")@Api(tags = "微信二维码生成接口")@CrossOriginpublic class WxApiController { @ApiOperation(value = "生成微信扫码登录二维码") @GetMapping("login") public String genQrConnect() { //定义微信生成二维码固定地址 //向地址里面拼接参数 //%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"; try { //redirecturl地址进行urlEncode编码 String redirectUrl = ConstantWeChatUtils.WX_OPEN_REDIRECT_URL; redirectUrl = URLEncoder.encode(redirectUrl, "utf-8"); //防止csrf攻击(跨站请求伪造攻击) //String state = UUID.randomUUID().toString().replaceAll("-", "");//一般情况下会使用一个随机数 String state = "onlineeducation";//此处state设置的是我内网穿透中的前置域名 //向%s位置传递参数值 String formatUrl = String.format( baseUrl, ConstantWeChatUtils.WX_OPEN_APP_ID, redirectUrl, state ); //重定向到拼接好的地址里面 return "redirect:"+formatUrl; }catch(Exception e) { return null; } }}
org.apache.httpcomponents httpclient 4.5.1 commons-io commons-io 2.6 com.google.code.gson gson 2.8.2
工具类提取地址:
提取码:3wuo
@Autowiredprivate UcenterMemberService memberService;//此处注入的为项目中用户模块的service/*** 1、获取回调参数* 2、从redis中读取state进行比对,异常则拒绝调用* 3、向微信的授权服务器发起请求,使用临时票据换取access_token* 4、使用上一步获取的openid查询数据库,判断当前用户是否已注册,如果已注册则直接进行登录操作* 5、如果未注册,则使用openid和access_token向微信的资源服务器发起请求,请求获取微信的用户信息* 5.1、将获取到的用户信息存入数据库 * 5.2、然后进行登录操作** @param code* @param state* @return*/@GetMapping("callback")@ApiOperation(value = "扫描成功后的回调方法")public String callback(String code,String state) { //code参数:临时票据,随机字符串,类似于手机验证码 //state参数:生成二维码传递state值 //1 获取code临时票据 //2 请求微信固定地址,得到acess_token和openid String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" + "?appid=%s" + "&secret=%s" + "&code=%s" + "&grant_type=authorization_code"; //拼接参数 baseAccessTokenUrl = String.format( baseAccessTokenUrl, ConstantWeChatUtils.WX_OPEN_APP_ID, ConstantWeChatUtils.WX_OPEN_APP_SECRET, code ); try { //请求这个带参数地址,得到acess_token和openid //使用httpclient String accessTokenResult = HttpClientUtils.get(baseAccessTokenUrl); // System.out.println("*********************accessTokenResult: "+accessTokenResult); //得到acess_token和openid Gson gson = new Gson(); //把accessTokenResult字符串转换map类型 HashMap accessTokenMap = gson.fromJson(accessTokenResult, HashMap.class); String access_token = (String)accessTokenMap.get("access_token"); String openid = (String)accessTokenMap.get("openid"); //3 拿着acess_token和openid再去请求微信固定地址,得到扫描人信息 String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" + "?access_token=%s" + "&openid=%s"; baseUserInfoUrl = String.format( baseUserInfoUrl, access_token, openid ); //请求地址 String userInfoResult = HttpClientUtils.get(baseUserInfoUrl); HashMap userInfoMap = gson.fromJson(userInfoResult, HashMap.class); String nickname = (String)userInfoMap.get("nickname"); String headimgurl = (String)userInfoMap.get("headimgurl"); //4 把获取微信扫描人信息添加数据库里面 //添加信息之前判断,根据openid进行判断,如果表存储相同用户信息不需要添加 //需要给用户设置哪些信息根据自己的表字段进行设置 UcenterMember member = memberService.getUserInfoByOpenId(openid); if(member == null) { //表不存在相同用户,进行添加 member = new UcenterMember(); member.setOpenid(openid); member.setNickname(nickname); member.setAvatar(headimgurl); memberService.save(member); } }catch(Exception e) { } return null;}
其中accessTokenResult中得到的数据为:
userInfoResult中得到的数据为:添加信息之前通过openid判断用户信息是否存在的代码
//根据openid查询扫码登录的用户是否存在@Overridepublic UcenterMember getUserInfoByOpenId(String openid) { QueryWrapperwrapper = new QueryWrapper<>(); wrapper.eq("openid",openid); UcenterMember member = baseMapper.selectOne(wrapper); return member;}
io.jsonwebtoken jjwt 0.7.0
public class JwtUtils { public static final String SUBJECT = "guli";//名字随意 //秘钥 public static final String APPSECRET = "guli";//名字随意 public static final long EXPIRE = 1000 * 60 * 30; //过期时间,毫秒,30分钟 /** * 根据对象生成jwt的字符串 * * @param member * @return */ public static String geneJsonWebToken(UcenterMember member) { if (member == null || StringUtils.isEmpty(member.getId()) || StringUtils.isEmpty(member.getNickname()) || StringUtils.isEmpty(member.getAvatar())) { return null; } String token = Jwts.builder().setSubject(SUBJECT) .claim("id", member.getId()) .claim("nickname", member.getNickname()) .claim("avatar", member.getAvatar()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + EXPIRE)) .signWith(SignatureAlgorithm.HS256, APPSECRET).compact(); return token; } /** * 根据jwt的token字符串,从字符串获取用户信息 * * @param token * @return */ public static Claims checkJWT(String token) { //claims类似于map集合 Claims claims = Jwts.parser().setSigningKey(APPSECRET).parseClaimsJws(token).getBody(); return claims; }}
在WxApiController.java的callback方法的最后添加如下代码
// 生成jwtString token = JwtUtils.geneJsonWebToken(member);//存入cookie//CookieUtils.setCookie(request, response, "guli_jwt_token", token);//因为端口号不同存在蛞蝓问题,cookie不能跨域,所以这里使用url重写return "redirect:http://localhost:3000?token=" + token;
在layout/defaullt.vue中打印获取的token值
export default { created() { console.log(this.$route.query.token) }}
(1)编写接口,根据token字符串获取用户信息
@PostMapping("getUserInfoToken/{token}")@ApiOperation(value = "根据token获取token里面的用户信息")public R getUserInfoToken(@PathVariable String token) { Claims claims = JwtUtils.checkJWT(token); String id = (String)claims.get("id"); String nickname = (String)claims.get("nickname"); String avatar = (String)claims.get("avatar"); UcenterMember member = new UcenterMember(); member.setId(id); member.setNickname(nickname); member.setAvatar(avatar); return R.ok().data("member",member);}
pages/register.vue
在整合前端添加微信扫码登录时,注意将href请求路径填写为自己后台的路径即可。
pages/login.vue
转载地址:http://mpshn.baihongyu.com/