文章目录

  • 一.技术以及框架选择
  • 二.功能需求
  • 三.功能具体实现
  • 1.登录流程
  • 2.代码实现
  • 2.1 小程序登录事件
  • 2.2 登录逻辑
  • 2.3 后台登录逻辑实现
  • 2.3.1 登录接口


最近接到小程序毕设业务业务,记录下开发过程,UI实现这些就没必要写了

记录一下登录功能实现,虽然很简单不值一提.

一.技术以及框架选择

后台开发框架:springboot

权限框架:spring Security

小程序开发:uni-app

二.功能需求

1.点击登录,后台签发token,之后每次请求都携带这个token以此鉴权,没有相关权限不给访问

三.功能具体实现

1.登录流程

微信小程序和Springboot整合微信登陆 springboot微信小程序授权登录_ide

第一步: 调用登录API,wx.login获得code,并将code发送到我们的后台

第二步: 后台接收到code后,再向微信登录凭证校验接口发起请求,携带参数有:小程序appId,AppSecret(小程序密钥)和刚拿到的code,参数没错便返回openId和session_key,参数错误

的话才会返回err相关数据(开始以为正确与否都会返回,结果不是)

第三步: 拿到返回来的相关数据与小程序前端传递过来的用户数据(头像昵称等)一起保存进数据库

第四步:签发登录token,并返回到小程序,小程序保存到Storage和vuex

2.代码实现

2.1 小程序登录事件

<button @click="loginAction" :plain="true" class="user-name" style="font-size: 35upx;border: none;">点击登录,记录点点滴滴..></button>

不再使用了:
开发能力: open-type=“getUserInfo” -> 获取用户账号信息,昵称头像等
函数: @getuserinfo=“login” -> 获取用户账号信息的回调函数,并在这里做登录逻辑实现

更新的代码

wx.getUserProfile 的API,详情请看官方文档

2.2 登录逻辑

这里将userInfo和code一起传到后台去,就可以完成登录同时保存用户数据

//微信用户登录
			loginAction(){
				var that = this;
				wx.getUserProfile({
				  desc: "获取你的昵称、头像、地区及性别",
				  success: res => {
				    console.log("新版userInfo",res)
					var userinfo = res.userInfo;
					uni.login({
					  provider: 'weixin',
					  success: function (loginRes) {
						  uni.showLoading({
						  	mask:true,
							title:"加载中..."
						  })
						  console.log("登录code",loginRes);
						// 获得登录凭证code,将其传到后台,进行最终的登录操作获取openId
						if(loginRes.code){
							userinfo['code'] = loginRes.code
							that.$http.post('/app/applet/login',userinfo).then(resp=>{
								//将数据保存在状态管理器中
								that.$store.commit("setUserInfo",resp.data) //
								//将数据保存在用户的手机内存中
								uni.setStorage({
								    key: 'userInfo',
								    data: resp.data,
								    success: function () {
										uni.hideLoading()
								    }
								});
							}).catch(err=>{
								console.log("登录失败");
								uni.showModal({
									content:"登录失败",
									showCancel:false
								})
								uni.hideLoading()
							})
						}
						uni.hideLoading()
					  }
					});
				  },
				  fail: res => {
				  	 //拒绝授权
				    // that.showErrorModal('您拒绝了请求');
				    return;
				  }
				})
			},

2.3 后台登录逻辑实现

2.3.1 登录接口
/**
     * auth.code2Session
     * https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
     * 返回值
     * @return  JSON 数据包
     *           属性	     类型	   说明
     *          openid	     string	  用户唯一标识
     *          session_key	 string	  会话密钥
     *          unionid	     string	  用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回,详见 UnionID 机制说明。
     *          errcode	     number	  错误码
     *          errmsg	     string	  错误信息
     *
     *          errcode 的合法值
     *
     *          值	         说明	                     最低版本
     *          -1	         系统繁忙,此时请开发者稍候再试
     *          0	         请求成功
     *          40029	     code 无效
     *          45011	     频率限制,每个用户每分钟100次
     */
    @PostMapping("login")
    public ResponseData login(@RequestBody JSONObject userInfo){
        System.out.println("登录"+userInfo.getString("code"));
        VAppletDTO appletDTO = vAppletService.get(); //获取小程序配置
        JSONObject jsonObject = WXUtils.authCode2Session(appletDTO.getAppId(), appletDTO.getAppSecret(), userInfo.getString("code"));
        if(jsonObject.get("errcode")!=null){
            //登录失败
            return new ResponseData().fail(ResponseCode.USER_LOGIN_FAIL.getCode(),"登录失败");
        }
        //登录成功,
        String openid = jsonObject.getString("openid");
        VUserDTO byOpenId = vUserService.getByOpenId(openid); //根据openId查询数据库中是否有这个用户
        VUserEntity entity =null;
        if(byOpenId==null){//没有当前登录用户,保存新用户数据
            byOpenId = new VUserDTO();
            //设置新数据
            byOpenId.setAvatar(userInfo.getString("avatarUrl"));
            byOpenId.setNickName(userInfo.getString("nickName"));
            byOpenId.setOpenId(openid);
            byOpenId.setUnionId(jsonObject.getString("unionid"));
            byOpenId.setSeesionKey(jsonObject.getString("session_key"));

            byOpenId.setGender(userInfo.getIntValue("gender"));
            byOpenId.setCountry(userInfo.getString("country"));
            byOpenId.setProvince(userInfo.getString("province"));
            byOpenId.setCity(userInfo.getString("city"));
            entity = vUserService.save(byOpenId);//将数据存进数据库
            //生成登录成功的token令牌
        }else {
            //设置新数据
            byOpenId.setAvatar(userInfo.getString("avatarUrl"));
            byOpenId.setNickName(userInfo.getString("nickName"));
            byOpenId.setOpenId(openid);
            byOpenId.setUnionId(jsonObject.getString("unionid"));
            byOpenId.setSeesionKey(jsonObject.getString("session_key"));
            vUserService.update(byOpenId);
            entity = ConvertUtils.sourceToTarget(byOpenId,VUserEntity.class);
        }
        //将权限放/角色入token中
        Map<String, Object> map = new HashMap<>();
        map.put(ResponseCode.ParamterUserIdKey,entity.getId());
        map.put("role","ROLE_user"); //默认小程序用户属于"user" 用户组,
        map.put("nickName",entity.getNickName());
        String token = null;
        try {
            token = XTokenUtils.createToken(map, ResponseCode.TokenExp);
            UserVO userVO = ConvertUtils.sourceToTarget(byOpenId, UserVO.class);
            userVO.setToken(token);
            return new ResponseData().success("登录成功",userVO);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ResponseData().fail("登录失败");
    }

注: spring Security用角色控制的记得加ROLE_前缀,

微信请求工具类

/**
 * @description: 微信请求工具类
 * @author: ※狗尾巴草
 * @date: 2021-03-22 22:57
 **/
public class WXUtils {

    /**
     * auth.code2Session
     * https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
     * 请求参数   属性	     类型	   默认值	必填	      说明
     * @param   appId	     string		         是	   小程序 appId
     * @param   secret	     string		         是	   小程序 appSecret
     * @param   jsCode	     string		         是	   登录时获取的 code
     *          grantType	 string		         是	   授权类型,此处只需填写 authorization_code
     * 返回值
     * @return  JSON 数据包
     *           属性	     类型	   说明
     *          openid	     string	  用户唯一标识
     *          session_key	 string	  会话密钥
     *          unionid	     string	  用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回,详见 UnionID 机制说明。
     *          errcode	     number	  错误码
     *          errmsg	     string	  错误信息
     *
     *          errcode 的合法值
     *
     *          值	         说明	                     最低版本
     *          -1	         系统繁忙,此时请开发者稍候再试
     *          0	         请求成功
     *          40029	     code 无效
     *          45011	     频率限制,每个用户每分钟100次
     */
    public static JSONObject authCode2Session(String appId, String secret, String jsCode) {

        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + secret + "&js_code=" + jsCode + "&grant_type=authorization_code";
        JSONObject jsonObject = Httprequest.get(url);
        //System.out.println(jsonObject);
        return jsonObject;
    }
}

简单写了个Httprequest工具类

/**
 * @description: Httprequest工具类
 * @author: ※狗尾巴草
 * @date: 2021-03-22 23:01
 **/
public class Httprequest {

    /**
     * @description: http请求--post请求
     * @time: 2019/12/22 0:11
     */
    public static JSONObject post(String url,Map<String, Object> data){
        HttpRequest httpRequest = new HttpRequest(url, "POST");
        httpRequest.form(data);
        return JSONObject.parseObject(httpRequest.body());
    }


    /**
     * @description: http请求--get请求
     * @time: 2019/12/22 0:11
     */
    public static JSONObject get(String url){
        return JSONObject.parseObject(HttpRequest.get(url).body());
    }
}

http工具的依赖

<dependency>
   <groupId>com.github.kevinsawicki</groupId>
   <artifactId>http-request</artifactId>
   <version>5.6</version>
</dependency>

在登录接口实现那里完成了tokan签发,最后添加权限拦截规则

来到security的配置类

微信小程序和Springboot整合微信登陆 springboot微信小程序授权登录_spring boot_02

.antMatchers("/user/**").hasAnyRole("user")

如此便完成了登录以及权限控制了