微信扫码登录

微信扫码 授权码模式

授权码模式流程
1.客户端向授权服务器请求授权,包括客户端标识、重定向URI等信息。
2.授权服务器验证客户端身份,验证通过后,向客户端发放授权码。
3.客户端使用授权码向授权服务器请求Access Token。
4.授权服务器验证授权码的有效性,验证通过后,向客户端发放Access Token。
5.客户端使用Access Token向资源服务器请求资源。
6.资源服务器验证Access Token的有效性,验证通过后,向客户端返回资源。
在这里插入图片描述

1.准备工作
网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。 在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。
2.请参考官方文档
https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
3.在前端
将微信登录二维码内嵌到自己页面

为了满足网站更定制化的需求,我们还提供了第二种获取code的方式,支持网站将微信登录二维码内嵌到自己页面中,用户使用微信扫码授权后通过JS将code返回给网站。 JS微信登录主要用途:网站希望用户在网站内就能完成登录,无需跳转到微信域下登录后再返回,提升微信登录的流畅性与成功率。 网站内嵌二维码微信登录JS实现办法:

步骤1:在页面中先引入如下JS文件(支持https):

http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
步骤2:在需要使用微信登录的地方实例以下JS对象:

 var obj = new WxLogin({
 self_redirect:true,
 id:"login_container", 
 appid: "", 
 scope: "", 
 redirect_uri: "",
  state: "",
 style: "",
 href: ""
 });

打开前端保证有二维码出现

4.在后端

在启动类上引入,或者自己新建配置类


//远程调用第三方接口
    @Bean
    RestTemplate restTemplate(){
        RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());
        return  restTemplate;
    }

pom引入依赖

        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </dependency>

controller

@Slf4j
@Controller
public class WxLoginController {

    @Autowired
    WxAuthService wxAuthService;

    @RequestMapping("/wxLogin")
    public String wxLogin(String code, String state) throws IOException {
        log.debug("微信扫码回调,code:{},state:{}", code, state);
        //远程调用微信请令牌,拿到令牌查询用户信息,将用户信息写入本项目数据库
        XcUser xcUser = wxAuthService.wxAuth(code);

        if (xcUser == null) {
        //返回错误的页面
            return "redirect:http://www.51xuecheng.cn/error.html";
        }
        String username = xcUser.getUsername();
        //http://www.51xuecheng.cn/sign.html改成自己需要跳转的页面,这里重定向登录页面
        return "redirect:http://www.51xuecheng.cn/sign.html?username=" + username + "&authType=wx";
    }
}

调用的业务层逻辑代码,自己改成自己的实体类和配置yml文件即可

@Service("wx_authservice")
public class WxAuthServiceImpl implements AuthService, WxAuthService {

    @Autowired
    XcUserMapper xcUserMapper;
    @Autowired
    XcUserRoleMapper xcUserRoleMapper;

    @Autowired
    WxAuthServiceImpl currentPorxy;

    @Autowired
    RestTemplate restTemplate;


    @Value("${weixin.appid}")
    String appid;
    @Value("${weixin.secret}")
    String secret;


    @Override
    public XcUser wxAuth(String code) {
        //申请令牌
        Map<String, String> access_token_map = getAccess_token(code);
        //访问令牌
        String access_token = access_token_map.get("access_token");
        String openid = access_token_map.get("openid");

        //携带令牌查询用户信息
        Map<String, String> userinfo = getUserinfo(access_token, openid);

        // 保存用户信息到数据库
        XcUser xcUser = currentPorxy.addWxUser(userinfo);


        return xcUser;
    }

    @Transactional
    public XcUser addWxUser(Map<String,String> userInfo_map){
        String unionid = userInfo_map.get("unionid");
        String nickname = userInfo_map.get("nickname");
        //根据unionid查询用户信息
        XcUser xcUser = xcUserMapper.selectOne(new LambdaQueryWrapper<XcUser>().eq(XcUser::getWxUnionid, unionid));
        if(xcUser !=null){
            return xcUser;
        }
        //向数据库新增记录
        xcUser = new XcUser();
        String userId= UUID.randomUUID().toString();
        xcUser.setId(userId);//主键
        xcUser.setUsername(unionid);
        xcUser.setPassword(unionid);
        xcUser.setWxUnionid(unionid);
        xcUser.setNickname(nickname);
        xcUser.setName(nickname);
        xcUser.setUtype("101001");//学生类型
        xcUser.setStatus("1");//用户状态
        xcUser.setCreateTime(LocalDateTime.now());
        //插入
        int insert = xcUserMapper.insert(xcUser);

        //向用户角色关系表新增记录
        XcUserRole xcUserRole = new XcUserRole();
        xcUserRole.setId(UUID.randomUUID().toString());
        xcUserRole.setUserId(userId);
        xcUserRole.setRoleId("17");//学生角色
        xcUserRole.setCreateTime(LocalDateTime.now());
        xcUserRoleMapper.insert(xcUserRole);
        return xcUser;

    }

    /**
     * 携带授权码申请令牌
     * https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
     *
     * {
     * "access_token":"ACCESS_TOKEN",
     * "expires_in":7200,
     * "refresh_token":"REFRESH_TOKEN",
     * "openid":"OPENID",
     * "scope":"SCOPE",
     * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
     * }
     * @param code 授权
     * @return
     */
    private Map<String,String> getAccess_token(String code){

        String url_template = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
        //最终的请求路径
        String url = String.format(url_template, appid, secret, code);

        //远程调用此url
        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, null, String.class);
        //获取响应的结果
        String result = exchange.getBody();
        //将result转成map
        Map<String,String> map = JSON.parseObject(result, Map.class);
        return map;


    }

    /**
     * 携带令牌查询用户信息
     *
     * https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
     *
     * {
     * "openid":"OPENID",
     * "nickname":"NICKNAME",
     * "sex":1,
     * "province":"PROVINCE",
     * "city":"CITY",
     * "country":"COUNTRY",
     * "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
     * "privilege":[
     * "PRIVILEGE1",
     * "PRIVILEGE2"
     * ],
     * "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
     *
     * }
     * @param access_token
     * @param openid
     * @return
     */
    private Map<String,String> getUserinfo(String access_token,String openid){

        String url_template = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
        String url = String.format(url_template, access_token, openid);

        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, null, String.class);

        //获取响应的结果
        String result = new String(exchange.getBody().getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
        //将result转成map
        Map<String,String> map = JSON.parseObject(result, Map.class);
        return map;

    }
}

//接口
public interface WxAuthService {

 /**
  *  微信扫码认证,申请令牌,携带令牌查询用户信息、保存用户信息到数据库
  * @param code 授权码
  * @return
  */
 public XcUser wxAuth(String code);
}

5.内网穿透测试,由于wx的接口需要返回响应给我们的服务,所以该模块必须暴露在公网,所以需要使用内网穿透
请参考
https://blog.csdn.net/qq_56533553/article/details/130173196

至此就可以调用第三方的接口获取到需要的用户信息了,注意这里只到了保存用户信息

微信扫码登录Angular是一种基于微信开放平台提供的二维码扫描技术,在Angular应用中实现场景化认证的过程。这种方式使得用户可以通过微信扫码的方式快速完成身份验证并登录到应用程序中,无需手动输入用户名和密码。 ### 实现步骤: #### 1. 注册微信开放平台账号 首先需要在微信公众平台上注册一个账号,并创建一个小程序或公众号,获取AppID和AppSecret。 #### 2. 配置Angular项目 在Angular项目中引入微信支付和授权的相关依赖库,如`ngx-wechat-login`等。这通常涉及安装相应的npm包。 ```bash # 使用 npm 安装示例 npm install ngx-wechat-login --save ``` #### 3. 引入服务 在 Angular 应用中引入微信登录相关的服务,并注入到需要使用此功能的组件中。 ```typescript import { WechatLoginService } from 'ngx-wechat-login'; constructor(private wechatLoginService: WechatLoginService) {} ``` #### 4. 创建登录功能 在组件中创建微信扫码登录的功能实现。通常包括调用微信登录接口、处理回调结果以及展示加载状态。 ```typescript export class LoginPage { loading = false; constructor(private wechatLoginService: WechatLoginService) {} startWechatLogin() { this.loading = true; // 调用微信登录API,此处假设调用的是wechatLoginService.startLogin() this.wechatLoginService.startLogin().subscribe( (response) => { console.log('成功响应', response); this.handleSuccess(response); }, (error) => { console.error('登录失败', error); this.handleFailure(error); } ); } handleSuccess(data) { // 处理成功的回调数据,可能包含用户信息等 console.log('登录成功', data); // 根据实际情况,可以跳转至主页面或其他操作 } handleFailure(err) { // 处理错误情况 console.log('登录失败', err); } } ``` #### 5. 显示二维码界面 在前端渲染界面中,添加一个按钮触发微信登录请求,然后展示一个二维码供用户扫码。 ```html <button (click)="startWechatLogin()">微信扫码登录</button> <div #qrCode></div> <!-- 添加模板引用 --> <ng-template #qrCode> <!-- 渲染二维码图片 --> <img src="{{ qrCodeUrl }}" alt="二维码"> </ng-template> ``` #### 6. 后端对接 后端需要设置好路由和控制器,用于接收来自微信的回调数据,验证用户身份并返回对应的信息给前端。 #### 7. 用户权限管理 根据用户通过微信登录获得的信息,更新或创建用户的会话状态和相关信息存储于数据库中。 ### 相关问题: 1. **如何优化微信扫码登录的用户体验?** 提高加载速度、简化交互流程、增强安全防护措施、提供反馈提示等都是优化体验的关键点。 2. **Angular中如何处理微信扫码登录的异常情况?** 对应的错误处理逻辑应该覆盖所有可能发生的异常场景,比如网络错误、服务器响应延迟、用户取消扫码等,避免应用崩溃。 3. **为什么选择微信扫码登录而非其他第三方登录方式?** 主要考虑的因素有安全性、用户基数大、易于集成、用户体验良好等。微信作为中国的主流社交软件之一,拥有庞大的用户群体和良好的品牌认知度,适合多种应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值