spring mvc实现微信小程序登录(前台+后台)

本文将详细的介绍微信小程序的登录流程以及在ssm框架下如何实现小程序用户登录(日后补上过滤器的配置。。。)

登录流程概要

主要的登录流程可以参考官方提供的一张流程图:

 

1.微信前台页面:

在微信版本更新之后,提高了安全机制,我们需要为用户提供一个授权按钮,让用户同意授权,页面中的button必须包含 open-type="getUserInfo"这个属性:

一般授权页面如下:

    <form bindsubmit="bindSave">
      <wxc-button type="success" size='large' btn-style='margin-top:10%;' open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo"
        value="同意授权登录"></wxc-button>
      <view style='width:100%;padding-left:30rpx;font-size: 30rpx;margin-top:50rpx;'>1. 同意当前小程序获取我的微信头像;</view>
      <view style='width:100%;padding-left:30rpx;font-size: 30rpx;margin-top:20rpx;'>2. 同意当前小程序获取我的微信昵称等其他信息;</view>
      <wxc-button type="danger" size='large' btn-style='margin-top:30rpx;' bindtap='rejectLogin' value="拒绝授权"></wxc-button>
    </form>

2.登录前台实现

当用户登录时,我们先去判断小程序缓存中用户的token存不存在:

  -----如果存在,将token传到后台去检查redis缓存中的用户信息是否失效:

    -----如果失效,前台将用户信息删除,重新调用登录接口。

    -----未失效,返回原页面,后台更新缓存失效时间。

  -----如果不存在,前台调用官方提供的小程序登录接口:wx.login(),获得它返回的code:

    -----code获取成功,前台调用wx.getSetting()获取授权以及用户的授权配置:

      -----用户授权成功,前台调用wx.getUserInfo()获取encryptedData(密文)和 iv(偏移向量

         ------以上都获取成功后,我们将codeencryptedData和iv全部传到后台。

         (code用来换取openid和sessionKey,encryptedData和iv用来获得并解密用户信息)

           -----如果后台获取用户信息成功,返回token和用户信息到前台,前台小程序在缓存中更新token和用户信息。

           登录成功。

     -----------------------任意一个步骤失败,提示用户无法登录。

 

微信小程序前台登录函数如下(下面这个函数较长,可以拆分,看的更清晰):

  login: function () {
    let that = this;
    let token = wx.getStorageSync("token");
    console.log("进入页面登录开始取token"+token);
    if (token) {
      console.log("如果token存在");
      wx.request({
        url: urlMangerData.api0_check_token,///wxma/user/check-token
        data: {
          token: token
        },
        success: function (res) {
          console.log("前台token存在,校验token后返回值"+JSON.stringify(res));
          //如果后台缓存已经不在了
          if (!res.data.success) {
            console.log("如果后台缓存已经失效了,小程序清空token和userinfo和openid");
            wx.removeStorageSync("token");
            wx.removeStorageSync("userInfo");
            that.login();
          } else {
            console.log("后台缓存中的信息也存在,直接返回");
            // 回到原来的地方
            wx.navigateBack();
          }
        }
      });
    }
    console.log("如果token不存在");
    //小程序登录,
    wx.login({
      success: function (res) {
        if(res.code){          
      wx.getSetting({
        success: res2 => {
          if (res2.authSetting["scope.userInfo"]) {
          wx.getUserInfo({
            success:datas=>{
              console.log("开始获取code和一些加密过的用户信息" + res.code);
              console.log("datas.encryptedData" + datas.encryptedData);
              wx.request({
                url: urlMangerData.api0_loginAuth,
                data: {
                  code: res.code,
                  encryptedData: datas.encryptedData,
                  iv: datas.iv
                },
                header: {
                  'content-type': 'application/json'
                },
                success: function (res) {
                  console.log("后台成功后得到返回值" + res.data.code);
                  if(res.data.code != 0) {
                    console.log("后台登录错误")
                    wx.hideLoading();
                    wx.showModal({
                      title: "提示",
                      content: "无法登录,请重试",
                      showCancel: false
                    });
                    return;
                  }
                  console.log("存储用户信息token" + res.data.token);
                  console.log("存储用户信息userInfo" + JSON.stringify(res.data.wxMaUserInfoExtends));
                  wx.setStorageSync("token", res.data.token);
                  wx.setStorageSync("userInfo", res.data.wxMaUserInfoExtends);
                  wx.setStorageSync("user_id", res.data.wxMaUserInfoExtends.user_id);
                  wx.navigateBack();           
              }
            });//request
            }
      })//getuserinfo
    }
  }
 })//getsetting
  }
}//success
})
}

再贴一下第一次登录时,控制台打印信息:

3.登录后台实现

当用户登录时,先检查前台传来的token在redis中是否存在:存在即更新redis中用户信息的失效时间,不存在则返回登录失效信息。

前台获得失效信息后,正常去调用获取用户信息接口,传入code,encryptedData和iv:

controller层:

    @RequestMapping(value = "/loginAuth", method = RequestMethod.GET, produces = "application/json; charset=utf-8")
    public String loginAuth(String code,String encryptedData,String iv) throws WxErrorException {
        if (StringUtils.isBlank(code)) {
            return "empty jscode";
        }
        //处理登录授权 获得openid和sessionkey,生成userid 并将session存到缓存中
        WxMaAuthResult result = 
        weixinMaService.dealLoginAuth(code,encryptedData,iv);
        return JsonUtils.objectToJson(result);
        
    }

service层:

    /**
     *  处理小程序登录授权
     */
    @Override
    public WxMaAuthResult dealLoginAuth(String  code,String data,String iv) {
        WxMaJscode2SessionResult session =new WxMaJscode2SessionResult();
        //调微信官方接口获得sesssion_key openid存到 session对象里
        try {
       //code换取sessionKey session
= wxMaService.getUserService().getSessionInfo(code); this.logger.info(session.getSessionKey()); this.logger.info(session.getOpenid()); } catch (WxErrorException e) { this.logger.error("获得sessionKey失败", e); } WxMaAuthResult wxMaAuthResult = new WxMaAuthResult();
     //该类用来存储用户信息 WxMaUserInfoExtends wxMaUserInfoExtends
= new WxMaUserInfoExtends(); WxMaUserInfo wxMaUserInfo = new WxMaUserInfo(); //暂时写死失效时间 int expire=3600; String sessionKey = session.getSessionKey(); String rawData = StringEscapeUtils.unescapeHtml4(data); // 解密用户信息 try {
       //sessionkey data iv 解密用户信息 wxMaUserInfo
= this.wxMaService.getUserService().getUserInfo(sessionKey, data, iv); } catch (Exception e) { // TODO Auto-generated catch block logger.error("解密用户信息失败"); e.printStackTrace(); } BeanUtils.copyProperties(wxMaUserInfo, wxMaUserInfoExtends); String third_session = Base64UUID.ramdomID(); wxMaAuthResult.setToken(third_session); String user_id = Base64UUID.ramdomID(); wxMaUserInfoExtends.setUser_id(user_id); //通过openid获取或新增用户信息 if(wxMaUserMapper.countAny(session.getOpenid())>0 ){ //存在 数据库更新 wxMaUserMapper.addWxMaUser(wxMaUserInfoExtends); //这里是将用户信息存到redis wxMaAuthSessionStorage.addWxMaSession(expire,third_session,wxMaUserInfoExtends); //不把openId传到前台 wxMaUserInfo.setOpenId(""); wxMaAuthResult.setIsReg(true); wxMaAuthResult.setSuccess(true); wxMaAuthResult.setWxMaUserInfoExtends(wxMaUserInfoExtends); } else { //不存在 数据库保存信息 wxMaUserMapper.addWxMaUser(wxMaUserInfoExtends); wxMaAuthSessionStorage.addWxMaSession(expire,third_session,wxMaUserInfoExtends); wxMaUserInfo.setOpenId(""); wxMaAuthResult.setSuccess(true); wxMaAuthResult.setIsReg(false); wxMaAuthResult.setWxMaUserInfoExtends(wxMaUserInfoExtends); } return wxMaAuthResult; }

实体类:

public class WxMaUserInfoExtends{
    
    private String user_id;

      private String openId;
      private String nickName;
      private String gender;
      private String language;
      private String city;
      private String province;
      private String country;
      private String avatarUrl;
      private String unionId;
      private Date create_date;
    
    ...
}
public class WxMaAuthResult extends WxMaJscode2SessionResult{

    private String code;

    private String token;
    
    private int expiresIn = -1;
    
    Boolean isReg = false; //是否保存过用户信息
    
    private boolean success;
    
    private WxMaUserInfoExtends wxMaUserInfoExtends;

    ...
    
}

注:还有一些是api提供的。

redis存取方法:

   @Autowired
    private JedisClient jedisClient;
    /**
     * 存放token和用户信息
     */
    //内部事务回滚不影响外部事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void addWxMaSession(int expire,String token,WxMaUserInfoExtends wxMaUserInfoExtends) {
        String json = JsonUtils.objectToJson(wxMaUserInfoExtends);
        try {
            jedisClient.set(token, json);
            jedisClient.expire(token, expire);        
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  //从缓存中获取用户信息
    @Override
    public WxMaAuthResult getWxMaSessionBy3rdKey(String token) {
        WxMaAuthResult wxMaAuthResult = new WxMaAuthResult();
        try {
            String json = jedisClient.get(token);
            if(json == null) {
                wxMaAuthResult.setSuccess(false);
                return wxMaAuthResult;
            }
            wxMaAuthResult.setSuccess(true);
            WxMaUserInfoExtends wxMaUserInfoExtends= JsonUtils.jsonToPojo(json, WxMaUserInfoExtends.class);
            wxMaAuthResult.setWxMaUserInfoExtends(wxMaUserInfoExtends);
            return wxMaAuthResult;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            wxMaAuthResult.setSuccess(false);
            return wxMaAuthResult;
        }
        
    }

 

注:这里使用了binarywang(一个github上的开源开发者)提供的API,该API封装了调用微信小程序官方接口的方法,并提供了一些小程序登录信息和用户信息的实体类,非常方便,有需要可以下载下来用:https://github.com/binarywang

后台大体流程:

1.我们用code去换取sessionKey和openId,再通过sessionKey,encryptedData和iv来解密用户信息(解密过程已经封装好了)。

2.生成一个随机字符串,将它作为key(token),用户信息作为value存入redis缓存并设置或更新失效时间。

3.返回登录结果和用户信息到前台。

 

转载于:https://www.cnblogs.com/xjx199403/p/10785356.html

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要实现微信小程序登录,可以使用Spring Security提供的OAuth 2.0协议实现。以下是基本的步骤: 1. 在微信开放平台中创建小程序,获取AppID和AppSecret。 2. 在Spring Security中配置OAuth 2.0客户端,设置微信小程序的AppID、AppSecret以及授权范围。 3. 创建一个Controller,处理微信小程序登录请求。在该Controller中,使用RestTemplate向微信平台发送请求,获取access_token和openid等信息。 4. 根据openid创建用户信息,并将用户信息存储在数据库中。 5. 在Spring Security中配置自定义的UserDetailsService,根据openid从数据库中查询用户信息并返回。 6. 在Spring Security中配置自定义的AuthenticationProvider,对用户进行认证。 具体实现细节可以参考Spring Security官方文档和示例代码。 ### 回答2: Spring Security可以用于实现微信小程序登录功能。下面是实现该功能的大概步骤: 1. 配置微信小程序开放平台的AppID和AppSecret,并获取sessionKey和openid。 2. 创建一个用于处理登录请求的接口,并在该接口中获取小程序传递的code参数。 3. 使用HTTP请求,向微信服务器发送code和之前配置的AppID、AppSecret,以获取openid和sessionKey。 4. 将获取到的openid和sessionKey存储在数据库中,作为用户的登录凭证。 5. 创建一个用户实体类,并添加相应的字段,比如openid、sessionKey等。 6. 实现一个自定义的UserDetailsService接口,用于根据openid查询用户信息。 7. 创建一个TokenGranter类,用于创建自定义的Token,包含openid和sessionKey等信息。 8. 实现一个自定义的AuthenticationProvider类,用于根据Token进行认证,并授权用户的访问权限。 9. 创建一个自定义的AuthenticationFilter类,用于处理登录请求,并验证用户的Token是否有效。 10. 将上述配置添加到Spring Security的配置类中,并配置相关的路径和权限。 通过上述步骤,我们可以实现微信小程序登录功能。用户通过小程序登录后,系统会根据openid查询用户信息,并通过Token进行认证和授权,确保用户可以访问相应的资源。同时,可以根据业务需求,在上述步骤中添加其他的逻辑处理。 ### 回答3: Spring Security是基于Java的安全框架,用于处理应用程序的认证和授权功能。要实现微信小程序登录,可以按照以下步骤进行: 1. 配置微信小程序登录:首先,需要在微信开发者平台注册小程序,并获取到小程序的AppID和AppSecret。然后,在Spring Security配置中,配置微信登录的认证提供商和回调URL。例如,在`SecurityConfig`类中可以使用`WeChatAuthenticationFilter`来处理微信登录流程和认证。 2. 创建WeChatAuthenticationFilter:继承`AbstractAuthenticationProcessingFilter`类,重写`attemptAuthentication`方法,实现微信登录的认证逻辑。在该方法中,将获取到的小程序code发送到微信服务器,通过code获取到微信用户的唯一标识OpenID和会话标识SessionKey。 3. 自定义AuthenticationProvider:创建一个自定义的`AuthenticationProvider`实现类,用于处理微信登录的认证逻辑。在该类中,可以根据微信的OpenID进行用户的查询和创建,生成用户的凭证信息,并返回一个实现了`Authentication`接口的认证对象。 4. 处理认证成功和失败的逻辑:在`SuccessfulAuthenticationHandler`中处理认证成功的逻辑,例如生成并返回JWT Token给前端;在`FailureAuthenticationHandler`中处理认证失败的逻辑,例如返回登录失败的提示信息给前端。 5. 配置微信登录接口和拦截器:配置微信登录的接口路径和访问权限,使用`WeChatAuthenticationFilter`拦截微信登录请求,进行认证处理。 通过以上步骤,就可以实现Spring Security与微信小程序登录功能。当用户通过微信小程序登录时,将会调用相应的微信登录接口,并经过认证流程完成登录。根据需求可以进行进一步的用户信息补全、鉴权和授权等功能的实现

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值