解决微信JS-SDK扫一扫功能接入以及出现签名无效 invalid signature

首先先说一下JS-SDK微信扫一扫功能接入方法:

开始时接入步骤,这里略带提一下,微信开发文档里面讲的很详细可以参考着写:

这里我重点说一下实现过程:

首先是页面上要引入相应的js文件,一行代码就足够了:

(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js

然后通过config接口注入权限验证配置:

首先看微信开发官方文档上介绍的:

这里需要从服务器端网页面传递的参数有timestamp、nonceStr和signature而appId和jsApiList都是固定的,这里直接写后台方法中写。首先,编写服务器端代码,生成timestamp、nonceStr和signature。

 在生成timestamp、nonceStr和signature的时候有两个参数需要获取 一个是access_token,另一个是jsapi_ticket。

access_token的获取需要AppId和AppSecret,获取位置如下:

获取地址如下发送GET请求

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

获取到access_token的方法在这里就不说了 这个网上案例很多 一般是不会出什么大错的  只要appId和appsercret正确,地址正确就OK。

重点说一下jsapi_ticket的获取(这里我只说一下我自己的获取方法:):

在通用工具类CommonUtil里面写个获取jsapi_ticket的方法:

其的的JSAPI_TICKET是我定义的获取jsapi_ticket的地址:

public final static String JSAPI_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";

方法:

然后根据获取到的access_token 调用此方法可获取到jsapi_ticket。

但是

确保一定缓存access_token和jsapi_ticket。

access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。

access_token和jsapi_ticket必须要在自己的服务器缓存,否则上线后会触发频率限制。请确保一定对token和ticket做缓存以减少2次服务器请求,不仅可以避免触发频率限制,请确保在服务上线前一定全局缓存access_token和jsapi_ticket,两者有效期均为7200秒,否则一旦上线触发频率限制,服务将不再可用。

详细的请仔细阅读文档。

获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了

上面的是微信开发文档中的签名生成规则:

具体生成过程代码可以不用自己写,微信开发文档提供的有demo示例:

 

是什么语言直接拿过来用就可以了!可以一边写一边琢磨签名算法的实现!

具体代码我就不贴出来了,基本上和上面的demo写的一样。

然后是Controller层的代码:

其中的JsApiTicketUtil.getJsApiTicket();是我从缓存中拿到的jsapi_ticket的键值对。

JsSignUtil.sign(jsapi_ticket,url); 就是demo中的获取签名的方法。

后台方法基本上完成了,接下来就是页面上的了:

在config中进行配置:

由于后台中生成的签名时间随机字符串什么的都是我在前台页面上用ajax获取到的,所有我写的配置为

这个示例是我写微信扫一扫的示例。其中的jsApiList可以有很多值,微信开发文档上都用。

然后写一个简单的扫一扫按钮 写个触发事件:

不管是按部就班还是自己琢磨着写,总算是写下来了,接下来就是对自己写的进行测试了:

页面上功能按部就班的写完点击扫一扫没反应???WFT?只好把配置文件config的debug打开了。

发现每次打开页面总是会提示签名无效:

几乎整整一两天时间都再整这个bug,现在已经解决了,接下来我说说解决过程:

首先肯定是先看微信开发文档上给出的解决办法,这个也是一般非常常用的解决办法:

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

截图:

如果出现签名无效 首先请按照官网文档上的方法一步步去排查,当然,排查过N次的同学就不用看了。

如果测试N次总是出现签名无效 ,那肯定是签名有问题。

如果用签名页面工具校验校验签名确实无误的话 ,那就是url的问题了。

微信开发文档常见错误报错上有这样一句话:

所以url要动态获取:可用location.href.split('#')[0]获取,而且需要encodeURIComponent,例如我写的:

然后后台获得还需要转换回来:

这是url的问题。一般这样写的话基本不会出什么错误了,要是还是出现签名无效,请继续往下看;

请确认你的AppId和AppSecret正确性;

确定通过AppId和AppSecret获取到的access_token全局缓存了并且有效。

确认获取到的jsapi_ticket是有效的 用到的access_token和appid是正确的。

确认获取access_token和jsapi_ticket的地址为:

 

请一定要仔细检查这个地址url,最好和官网文档上的对着一遍,看清楚是获取什么的地址栏!

最后再补充一点:

在查找错误的时候,我在百度上看到有人这样说:

上面的两个方法:是签名算法中的随机数和时间戳,首先请注意时间单位是秒 不是毫秒,其次是上面的随机数,官网文档上用的UUID获取的随机数,但是网上有人说必须是16位的,我这里写的也是16位的,如果经过上面的还报错的话

可以试试是不是这个的问题,时间紧我也没试呢!

遇到问题一定要先去仔细阅读文档,大部分答案都在文档中,都是自己粗心大意犯下的错。然后去百度,一步步排查,想不出来就想点别的总会解决的。

不说了,溜了溜了。

给个微信开发文档的路径:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432

要在Spring Security中使用微信扫码登录,您需要完成以下步骤: 1. 在微信开放平台上创建应用程序并配置授权域名。 2. 在应用程序中创建一个扫码登录的方式,获取重定向URL和state参数。 3. 在Spring Security配置中添加一个OAuth2客户端,包括客户端ID、客户端密钥、授权域和重定向URL。 4. 创建一个自定义的OAuth2认证过滤器,用于处理微信回调请求。 以下是一个简单的示例,演示如何在Spring Security中使用微信扫码登录: ``` @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private OAuth2AuthorizedClientService authorizedClientService; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/login/**").permitAll() .anyRequest().authenticated() .and() .oauth2Login() .redirectionEndpoint() .baseUri("/login/oauth2/code/wechat") .and() .userInfoEndpoint() .userService(wechatOAuth2UserService()) .and() .authorizedClientService(authorizedClientService) .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/") .permitAll(); } @Bean public OAuth2UserService<OAuth2UserRequest, OAuth2User> wechatOAuth2UserService() { return new WechatOAuth2UserService(); } private static class WechatOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> { @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { // 获取微信用户信息 Map<String, Object> userInfo = userRequest.getAdditionalParameters(); String openid = (String) userInfo.get("openid"); String nickname = (String) userInfo.get("nickname"); String avatarUrl = (String) userInfo.get("headimgurl"); // 构造OAuth2User对象 return new DefaultOAuth2User(Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")), userInfo, "openid"); } } @Bean public OAuth2AuthorizedClientRepository authorizedClientRepository() { return new HttpSessionOAuth2AuthorizedClientRepository(); } @Bean public OAuth2AuthorizedClientService authorizedClientService( OAuth2ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientRepository authorizedClientRepository) { return new DefaultOAuth2AuthorizedClientService(clientRegistrationRepository, authorizedClientRepository); } @Bean public ClientRegistrationRepository clientRegistrationRepository() { // 配置微信OAuth2客户端 ClientRegistration wechat = ClientRegistration.withRegistrationId("wechat") .clientId("your-client-id") .clientSecret("your-client-secret") .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}") .scope("snsapi_login") .authorizationUri("https://open.weixin.qq.com/connect/qrconnect") .tokenUri("https://api.weixin.qq.com/sns/oauth2/access_token") .userInfoUri("https://api.weixin.qq.com/sns/userinfo") .userNameAttributeName("openid") .clientName("Wechat") .build(); return new InMemoryClientRegistrationRepository(wechat); } @Bean public OAuth2AuthorizationRequestRedirectFilter oauth2AuthorizationRequestRedirectFilter( OAuth2AuthorizedClientService authorizedClientService) { // 自定义OAuth2认证过滤器,用于处理微信回调请求 OAuth2AuthorizationRequestRedirectFilter filter = new OAuth2AuthorizationRequestRedirectFilter( clientRegistrationRepository(), authorizedClientRepository()); filter.setAuthorizationRequestRepository( new HttpSessionOAuth2AuthorizationRequestRepository()); filter.setAuthorizationUri("https://open.weixin.qq.com/connect/qrconnect"); filter.setPrincipalExtractor(new OAuth2AccessTokenResponseClientAdapter( new DefaultOAuth2AccessTokenResponseClient()).getPrincipalExtractor()); filter.setAuthorizationClientService(authorizedClientService); return filter; } } ``` 您需要替换上述代码中的`your-client-id`和`your-client-secret`为您的微信应用程序的客户端ID和客户端密钥。 此外,您还需要编写一个控制器来处理登录页面和回调URL: ``` @Controller public class LoginController { @Autowired private OAuth2AuthorizedClientService authorizedClientService; @GetMapping("/login") public String login(HttpServletRequest request, Model model) { // 创建扫码登录URL和state参数 String redirectUrl = "http://" + request.getServerName() + ":" + request.getServerPort() + "/login/oauth2/code/wechat"; String state = UUID.randomUUID().toString().replaceAll("-", ""); // 将state参数存储在会话中 request.getSession().setAttribute("state", state); // 构造微信扫码登录URL String qrCodeUrl = "https://open.weixin.qq.com/connect/qrconnect?appid=your-app-id&redirect_uri=" + URLEncoder.encode(redirectUrl, "UTF-8") + "&response_type=code&scope=snsapi_login&state=" + state + "#wechat_redirect"; model.addAttribute("qrCodeUrl", qrCodeUrl); return "login"; } @GetMapping("/login/oauth2/code/wechat") public String loginCallback(HttpServletRequest request, HttpServletResponse response, @RequestParam("code") String code, @RequestParam("state") String state, Authentication authentication) throws IOException { // 验证state参数是否匹配 String sessionState = (String) request.getSession().getAttribute("state"); if (!state.equals(sessionState)) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid state parameter"); return null; } // 使用OAuth2AuthorizedClientService获取访问令牌 OAuth2AuthorizedClient authorizedClient = authorizedClientService.loadAuthorizedClient("wechat", authentication.getName()); String accessToken = authorizedClient.getAccessToken().getTokenValue(); // 处理用户登录逻辑 // ... return "redirect:/"; } } ``` 在`/login`请求中,我们构造了一个微信扫码登录的URL,并将其添加到模型中返回给用户。在`/login/oauth2/code/wechat`请求中,我们验证了回调请求中的state参数,并使用`OAuth2AuthorizedClientService`获取访问令牌,然后处理用户登录逻辑。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值