微信小程序-登录

2023-12-13 04:31:24

一、引言

????微信小程序的登录可以说是必备的门户,作者今天介绍一下微信小程序如何登录。

图片

二、前端

1、wxml

????? wxml其实和前端一样,就是html的意思。

????其实就是给两个按钮触发,可以使用微信直接登录,可以让用户注册账号进行登录。

<view class="container">
  <view class="login-box">
    <button type="primary" class="wx-login-btn" bindtap="getUserProfile">微信直接登录</button>
    <button type="primary" class="account-login-btn" bindtap="accountLogin">账号登录</button>
  </view>
</view>

2、微信直接登录

????重点在于很多功能都必须使用微信用户的openid,比如给他发消息,这就是每个微信用户的唯一编码,拿不到用户基本什么功能都用不了。

????这个和用户的密码之类的毫无关系,也根本影响不到用户,微信的安全还是很严的

getUserProfile(e) {
  // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
  // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
  wx.getUserProfile({
    desc: '用于完善资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
    success: (res) => {
      user.checkLogin().catch(() => {
        user.loginByWeixin(res.userInfo).then(res => {
          console.log('微信登录成功');
          app.globalData.hasLogin = true;
          wx.navigateBack({
            delta: 1
          })
        }).catch((err) => {
          app.globalData.hasLogin = false;
          util.showErrorToast('微信登录失败');
        });
      });
    },
    fail: (res) => {
      app.globalData.hasLogin = false;
      util.showErrorToast('微信登录失败');
    }
  });
},

/**
 * 调用微信登录
 */
function loginByWeixin(userInfo) {
  let shareUserId = wx.getStorageSync('shareUserId');
  if (!shareUserId || shareUserId =='undefined'){
    shareUserId = 1;
  }
  return new Promise(function(resolve, reject) {
    return login().then((res) => {
      //登录远程服务器
      util.request(api.AuthLoginByWeixin, {
        code: res.code,
        userInfo: userInfo,
        shareUserId: shareUserId
      }, 'POST').then(res => {
        if (res.errno === 0) {
          //存储用户信息
          wx.setStorageSync('userInfo', res.data.userInfo);
          wx.setStorageSync('token', res.data.token);

          resolve(res);
        } else {
          console.log(res);
          reject(res);
        }
      }).catch((err) => {
        console.log(err);
        reject(err);
      });
    }).catch((err) => {
      console.log(err);
      reject(err);
    })
  });
}

3、账户登录

????这个和微信直接登录的区别就是不会把一些昵称之类的带过去,和WEB网站一样可以进行注册就行。

????个人注册的微信小程序有点坑,不给拿用户的手机号。

<view class="container">
    <view class="form-box">

        <view class="form-item">
            <input class="username" value="{{username}}" bindinput="bindUsernameInput" placeholder="账号"/>
            <image wx:if="{{ username.length > 0 }}" id="clear-username" class="clear"
                   src="/static/images/clear_input.png" catchtap="clearInput"></image>
        </view>

        <view class="form-item">
            <input class="password" value="{{password}}" password bindinput="bindPasswordInput" placeholder="密码"/>
            <image class="clear" id="clear-password" wx:if="{{ password.length > 0 }}"
                   src="/static/images/clear_input.png" catchtap="clearInput"></image>
        </view>

        <!-- <view class="form-item-code" wx-if="{{loginErrorCount >= 3}}">
           <view class="form-item code-item">
               <input class="code" value="{{code}}" bindinput="bindCodeInput" placeholder="验证码"/>
               <image class="clear" id="clear-code" wx:if="{{ code.length > 0 }}" src="/static/images/clear_input.png" catchtap="clearInput"></image>
           </view>
           <image class="code-img" src="https://dl.reg.163.com/cp?pd=yanxuan_web&pkid=SkeBZeG&random=1489903563234"></image>
       </view>  -->

        <button type="primary" class="login-btn" bindtap="accountLogin">账号登录</button>

        <view class="form-item-text">
            <navigator url="/pages/auth/register/register" class="register">注册账号</navigator>
<!--            <navigator url="/pages/auth/reset/reset" class="reset">忘记密码</navigator>-->
        </view>
    </view>
</view>
accountLogin: function() {
  var that = this;

  if (this.data.password.length < 1 || this.data.username.length < 1) {
    wx.showModal({
      title: '错误信息',
      content: '请输入用户名和密码',
      showCancel: false
    });
    return false;
  }

  wx.request({
    url: api.AuthLoginByAccount,
    data: {
      username: that.data.username,
      password: that.data.password
    },
    method: 'POST',
    header: {
      'content-type': 'application/json'
    },
    success: function(res) {
      if (res.data.errno == 0) {
        that.setData({
          loginErrorCount: 0
        });
        app.globalData.hasLogin = true;
        wx.setStorageSync('userInfo', res.data.data.userInfo);
        wx.setStorage({
          key: "token",
          data: res.data.data.token,
          success: function() {
            wx.switchTab({
              url: '/pages/ucenter/index/index'
            });
          }
        });
      } else {
        that.setData({
          loginErrorCount: that.data.loginErrorCount + 1
        });
        app.globalData.hasLogin = false;
        util.showErrorToast('账户登录失败');
      }
    }
  });
},
bindUsernameInput: function(e) {

  this.setData({
    username: e.detail.value
  });
},
bindPasswordInput: function(e) {

  this.setData({
    password: e.detail.value
  });
},
bindCodeInput: function(e) {

  this.setData({
    code: e.detail.value
  });
},
clearInput: function(e) {
  switch (e.currentTarget.id) {
    case 'clear-username':
      this.setData({
        username: ''
      });
      break;
    case 'clear-password':
      this.setData({
        password: ''
      });
      break;
    case 'clear-code':
      this.setData({
        code: ''
      });
      break;
  }
}

三、后端

1、pom

<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-miniapp</artifactId>
    <version>4.1.0</version>
</dependency>

2、配置

sh:
  # 开发者应该设置成自己的wx相关信息
  wx:
    app-id: **
    app-secret: **

3、微信直接登录

????重点有两个

????一个是要通过微信的WxMaService获取openid和sessionKey

????另外一个是要放在缓存防止登录过期

@PostMapping("login_by_wx")
public Object loginByWx(@RequestBody WxLoginInfo wxLoginInfo, HttpServletRequest request) {
    logger.info("【请求开始】微信登录,请求参数,wxLoginInfo:{}", wxLoginInfo.toString());

    String code = wxLoginInfo.getCode();
    UserInfo userInfo = wxLoginInfo.getUserInfo();
    if (code == null || userInfo == null) {
        return ResponseUtil.badArgument();
    }

    Integer shareUserId = wxLoginInfo.getShareUserId();
    String sessionKey = null;
    String openId = null;
    try {
        WxMaJscode2SessionResult result = wxService.getUserService().getSessionInfo(code);
        sessionKey = result.getSessionKey();
        openId = result.getOpenid();
    } catch (Exception e) {
        e.printStackTrace();
    }

    if (sessionKey == null || openId == null) {
        logger.error("微信登录,调用官方接口失败:{}", code);
        return ResponseUtil.fail();
    }

    ArriveUser user = userService.queryByOid(openId);

    if (user == null) {
        user = new ArriveUser();
        user.setUsername(openId);
        user.setPassword(openId);
        user.setWeixinOpenid(openId);
        user.setAvatar(userInfo.getAvatarUrl());
        user.setNickname(userInfo.getNickName());
        user.setGender(userInfo.getGender());
        user.setUserLevel((byte) 0);
        user.setStatus((byte) 0);
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(IpUtil.client(request));
        user.setShareUserId(shareUserId);

        userService.add(user);

    } else {
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(IpUtil.client(request));
        if (userService.updateById(user) == 0) {
            return ResponseUtil.updatedDataFailed();
        }
    }

    // token
    UserToken userToken = null;
    try {
        userToken = UserTokenManager.generateToken(user.getId());
    } catch (Exception e) {
        logger.error("微信登录失败,生成token失败:{}", user.getId());
        e.printStackTrace();
        return ResponseUtil.fail();
    }
    userToken.setSessionKey(sessionKey);

    Map<Object, Object> result = new HashMap<Object, Object>();
    result.put("token", userToken.getToken());
    result.put("tokenExpire", userToken.getExpireTime().toString());
    userInfo.setUserId(user.getId());
    if (!StringUtils.isEmpty(user.getMobile())) {// 手机号存在则设置
        userInfo.setPhone(user.getMobile());
    }
    try {
        String registerDate = DateTimeFormatter.ofPattern("yyyy-MM-dd")
                .format(user.getAddTime() != null ? user.getAddTime() : LocalDateTime.now());
        userInfo.setRegisterDate(registerDate);
        userInfo.setStatus(user.getStatus());
        userInfo.setUserLevel(user.getUserLevel());// 用户层级
        userInfo.setUserLevelDesc(UserTypeEnum.getInstance(user.getUserLevel()).getDesc());// 用户层级描述
    } catch (Exception e) {
        logger.error("微信登录:设置用户指定信息出错:" + e.getMessage());
        e.printStackTrace();
    }
    result.put("userInfo", userInfo);

    logger.info("【请求结束】微信登录,响应结果:{}", (result));
    return ResponseUtil.ok(result);
}

4、账号登录

????先得注册

@PostMapping("register")
    public Object register(@RequestBody String body, HttpServletRequest request) {
        logger.info("【请求开始】账号注册,请求参数,body:{}", body);

        String username = JacksonUtil.parseString(body, "username");
        String password = JacksonUtil.parseString(body, "password");
//        String mobile = JacksonUtil.parseString(body, "mobile");
//        String code = JacksonUtil.parseString(body, "code");
        String wxCode = JacksonUtil.parseString(body, "wxCode");

        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)
                || StringUtils.isEmpty(wxCode)
//                || StringUtils.isEmpty(code)
        ) {
            return ResponseUtil.badArgument();
        }

        List<ArriveUser> userList = userService.queryByUsername(username);
        if (userList.size() > 0) {
            logger.error("请求账号注册出错:{}", AUTH_NAME_REGISTERED.desc());
            return WxResponseUtil.fail(AUTH_NAME_REGISTERED);
        }

//        userList = userService.queryByMobile(mobile);
//        if (userList.size() > 0) {
//            logger.error("请求账号注册出错:{}", AUTH_MOBILE_REGISTERED.desc());
//            return WxResponseUtil.fail(AUTH_MOBILE_REGISTERED);
//        }
//        if (!RegexUtil.isMobileExact(mobile)) {
//            logger.error("请求账号注册出错:{}", AUTH_INVALID_MOBILE.desc());
//            return WxResponseUtil.fail(AUTH_INVALID_MOBILE);
//        }
        // 判断验证码是否正确
//        String cacheCode = CaptchaCodeManager.getCachedCaptcha(mobile);
//        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code)) {
//            logger.error("请求账号注册出错:{}", AUTH_CAPTCHA_UNMATCH.desc());
//            return WxResponseUtil.fail(AUTH_CAPTCHA_UNMATCH);
//        }

        String openId = null;
        try {
            WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(wxCode);
            openId = result.getOpenid();
        } catch (Exception e) {
            logger.error("请求账号注册出错:{}", AUTH_OPENID_UNACCESS.desc());
            e.printStackTrace();
            return WxResponseUtil.fail(AUTH_OPENID_UNACCESS);
        }
        userList = userService.queryByOpenid(openId);
        if (userList.size() > 1) {
            return ResponseUtil.serious();
        }
        if (userList.size() == 1) {
            ArriveUser checkUser = userList.get(0);
            String checkUsername = checkUser.getUsername();
            String checkPassword = checkUser.getPassword();
            if (!checkUsername.equals(openId) || !checkPassword.equals(openId)) {
                logger.error("请求账号注册出错:{}", AUTH_OPENID_BINDED.desc());
                return WxResponseUtil.fail(AUTH_OPENID_BINDED);
            }
        }

        ArriveUser user = null;
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodedPassword = encoder.encode(password);
        user = new ArriveUser();
        user.setUsername(username);
        user.setPassword(encodedPassword);
//        user.setMobile(mobile);
        user.setWeixinOpenid(openId);
//        user.setAvatar(CommonConstant.DEFAULT_AVATAR);
        user.setNickname(username);
        user.setGender((byte) 0);
        user.setUserLevel((byte) 0);
        user.setStatus((byte) 0);
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(IpUtil.client(request));
        userService.add(user);

        // userInfo
        UserInfo userInfo = new UserInfo();
        userInfo.setNickName(username);
        userInfo.setAvatarUrl(user.getAvatar());

        // token
        UserToken userToken = null;
        try {
            userToken = UserTokenManager.generateToken(user.getId());
        } catch (Exception e) {
            logger.error("账号注册失败,生成token失败:{}", user.getId());
            e.printStackTrace();
            return ResponseUtil.fail();
        }

        Map<Object, Object> result = new HashMap<Object, Object>();
        result.put("token", userToken.getToken());
        result.put("tokenExpire", userToken.getExpireTime().toString());
        result.put("userInfo", userInfo);

        logger.info("【请求结束】账号注册,响应结果:{}", (result));
        return ResponseUtil.ok(result);
    }

????然后再登录

@PostMapping("login")
public Object login(@RequestBody String body, HttpServletRequest request) {
    logger.info("【请求开始】账户登录,请求参数,body:{}", body);

    String username = JacksonUtil.parseString(body, "username");
    String password = JacksonUtil.parseString(body, "password");
    if (username == null || password == null) {
        return ResponseUtil.badArgument();
    }

    List<ArriveUser> userList = userService.queryByUsername(username);
    ArriveUser user = null;
    if (userList.size() > 1) {
        logger.error("账户登录 出现多个同名用户错误,用户名:{},用户数量:{}", username, userList.size());
        return ResponseUtil.serious();
    } else if (userList.size() == 0) {
        logger.error("账户登录 用户尚未存在,用户名:{}", username);
        return ResponseUtil.badArgumentValue();
    } else {
        user = userList.get(0);
    }

    BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
    if (!encoder.matches(password, user.getPassword())) {
        logger.error("账户登录 ,错误密码:{},{}", password, AUTH_INVALID_ACCOUNT.desc());// 错误的密码打印到日志中作为提示也无妨
        return WxResponseUtil.fail(AUTH_INVALID_ACCOUNT);
    }

    // userInfo
    UserInfo userInfo = new UserInfo();
    userInfo.setNickName(username);
    userInfo.setAvatarUrl(user.getAvatar());

    try {
        LocalDateTime dateTime = user.getAddTime() != null ? user.getAddTime() : LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String registerDate = dateTime.format(formatter);
        userInfo.setRegisterDate(registerDate);
        userInfo.setStatus(user.getStatus());
        userInfo.setUserLevel(user.getUserLevel());// 用户层级
        userInfo.setUserLevelDesc(UserTypeEnum.getInstance(user.getUserLevel()).getDesc());// 用户层级描述
    } catch (Exception e) {
        logger.error("账户登录:设置用户指定信息出错:" + e.getMessage());
        e.printStackTrace();
    }

    // token
    UserToken userToken = null;
    try {
        userToken = UserTokenManager.generateToken(user.getId());
    } catch (Exception e) {
        logger.error("账户登录失败,生成token失败:{}", user.getId());
        e.printStackTrace();
        return ResponseUtil.fail();
    }

    Map<Object, Object> result = new HashMap<Object, Object>();
    result.put("token", userToken.getToken());
    result.put("tokenExpire", userToken.getExpireTime().toString());
    result.put("userInfo", userInfo);

    logger.info("【请求结束】账户登录,响应结果:{}", (result));
    return ResponseUtil.ok(result);
}

5、用户token

public class UserTokenManager {
   private static Map<String, UserToken> tokenMap = new HashMap<>();
   private static Map<Integer, UserToken> idMap = new HashMap<>();

   public static Integer getUserId(String token) {
      UserToken userToken = tokenMap.get(token);
      if (userToken == null) {
         return null;
      }

      if (userToken.getExpireTime().isBefore(LocalDateTime.now())) {
         tokenMap.remove(token);
         idMap.remove(userToken.getUserId());
         return null;
      }

      return userToken.getUserId();
   }

   public static UserToken generateToken(Integer id) {
      UserToken userToken = null;

      // userToken = idMap.get(id);
      // if(userToken != null) {
      // tokenMap.remove(userToken.getToken());
      // idMap.remove(id);
      // }

      String token = CharUtil.getRandomString(32);
      while (tokenMap.containsKey(token)) {
         token = CharUtil.getRandomString(32);
      }

      LocalDateTime update = LocalDateTime.now();
      LocalDateTime expire = update.plusDays(1);

      userToken = new UserToken();
      userToken.setToken(token);
      userToken.setUpdateTime(update);
      userToken.setExpireTime(expire);
      userToken.setUserId(id);
      tokenMap.put(token, userToken);
      idMap.put(id, userToken);

      return userToken;
   }

   public static String getSessionKey(Integer userId) {
      UserToken userToken = idMap.get(userId);
      if (userToken == null) {
         return null;
      }

      if (userToken.getExpireTime().isBefore(LocalDateTime.now())) {
         tokenMap.remove(userToken.getToken());
         idMap.remove(userId);
         return null;
      }

      return userToken.getSessionKey();
   }

   public static void removeToken(Integer userId) {
      UserToken userToken = idMap.get(userId);
      String token = userToken.getToken();
      idMap.remove(userId);
      tokenMap.remove(token);
   }
}

四、总结

????微信小程序的登录还是比较麻烦的,安全是微信能拥有这么大用户体量的原因之一,开发或者调试过程中遇到问题,欢迎和作者沟通,也可以关注作者的微信公众号:胖当当技术。

文章来源:https://blog.csdn.net/m0_69270256/article/details/134956516
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。