微信小程序登录授权开发

一认识开发工具

开发界面说明
在这里插入图片描述
1, wxml主要用来布局组件的(相当于大楼结构)
如:楼有几层,每层有多少房间,有什么设备
2, wxss主要决定显示样式(决定大楼的样式)
如:颜色,大小,宽高等
3, js主要用来处理逻辑(决定大楼具备哪些功能)
如:大楼具有电梯功能,空调制冷,灯光,供水,供电,主要是为了大厦的运行。

二级接口

官方参考文档专业解释

在这里插入图片描述
参考:添加链接描述

wx.getUserProfile(Object object) 获取用户信息

获取用户信息。页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo

  • 前端xml页面单机事件绑定wx.getUserProfile
    在这里插入图片描述
<!-- 没有用户信息就绑定登录事件 -->
<button wx:if="{{!userInfo}}" bindtap="login">授权登录</button>
<view wx:else class="root">
  <image class="touxiang" src="{{userInfo.avatarUrl}}"></image>
  <text class="nicheng">{{userInfo.nickName}}</text>
  <button bindtap="loginOut">退出登录</button>
</view>
  • 触及获取用户信息接口
Page({
  data: {
    userInfo: ''
  },
  onLoad() {
    let user = wx.getStorageSync('user')
    console.log('进入小程序的index页面获取缓存', user)
    this.setData({
      userInfo: user
    })
  },

  // 授权登录
  login() {
    wx.getUserProfile({
      desc: '必须授权才可以继续使用',
      success: res => {
        let user = res.userInfo
        // 把用户信息缓存到本地
        wx.setStorageSync('user', user)
        console.log("用户信息", user)
        this.setData({
          userInfo: user
        })
      },
      fail: res => {
        console.log('授权失败', res)
      }
    })
  },
  // 退出登录
  loginOut() {
    this.setData({
      userInfo: ''
    })
    wx.setStorageSync('user', null)
  }
})

在这里插入图片描述
在这里插入图片描述

wx.login(Object object) 获取code

1.调用此接口获取登录凭证(code)进而换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key)
2.然后我们拿这个code去自己的服务器换取用户openid和session_key
3.code是临时的,有效时间5分钟,
4.不是每次wx.login都会更新session_key,session_key的有效性微信是不会告诉开发者的,可以自定义登录状态会话session的有效性,也可以通过 auth.code2Session 接口更新服务器存储的 session_key
参考地址
5…openId 是不变的,如果有坏人拿着别人的 openId 来进行请求,那么就会出现冒充的情况。所以我们建议开发者可以自己在后台生成一个拥有有效期的 第三方session 来做登录态,用户每隔一段时间都需要进行更新以保障数据的安全性。

在这里插入图片描述

  // 授权登录
  login() {
    wx.getUserProfile({
      desc: '必须授权才可以继续使用',
      success: res => {
        let user = res.userInfo
        // 把用户信息缓存到本地
        wx.setStorageSync('user', user)
        console.log("用户信息", user)
        this.setData({
          userInfo: user
        })
      // 获取code
        wx.login({
          success (res) {
            if (res.code) {
              //发起网络请求
              // wx.request({
              //   url: 'https://example.com/onLogin',
              //   data: {
              //     code: res.code
              //   }
              // })
              console.log("获取到登录凭证:",res.code)
            } else {
              console.log('登录失败!' + res.errMsg)
            }
          }
        })

      },
      fail: res => {
        console.log('授权失败', res)
      }
    })
   
  }

在这里插入图片描述

auth.code2Session 获取appID

通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程
登录地址:
GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
参考:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html

如何获取微信小程序/微信公众号的AppId和AppSecret

前端完整代码

index.js

Page({
  data: {
    userInfo: ''
  },
  onLoad() {
    let user = wx.getStorageSync('user')
    console.log('进入小程序的index页面获取缓存', user)
    this.setData({
      userInfo: user
    })
  },

  // 授权登录
  login() {
    wx.getUserProfile({
      desc: '必须授权才可以继续使用',
      success: res => {
        let user = res.userInfo
        // 把用户信息缓存到本地
        wx.setStorageSync('user', user)
        console.log("用户信息是:", user)
        this.setData({
          userInfo: user
        })
      // 获取code
        wx.login({
          success (res) {
            if (res.code) {
              console.log("code是:", res.code)
              console.log("用户头像是:", user.avatarUrl)
              console.log("用户昵称是:", user.nickName)
              console.log("用户性别1是男性:", user.gender)
              //发起网络请求
              wx.request({
                method:'POST',
                header: {
                  'content-type': 'application/json'
                },
                url: 'http://127.0.0.1:19092/wechat/login',
                data: {
                  code: res.code,
                  ninck: user.nickName,
                  avaurl: user.avatarUrl,
                  sex: user.gender

                },
                dataType:'json',
                success: function(msg) {
                  if (msg) {
                
                  console.log('msg为:' +JSON.stringify(msg));
                  console.log('获取到的用户token为:' + msg.data.token);
                  //可以把token保存到本地缓存,前后端携带token交互
                  wx.setStorageSync('token', msg.data.token);
                  } else {
                    console.log('获取不到数据'+msg);
                  }
                  
                }
              })
              
            } else {
              console.log('登录失败!' + res.errMsg)
            }
          }
        })

      },
      fail: res => {
        console.log('授权失败', res)
      }
    })
   
  },
  // 退出登录
  loginOut() {
    this.setData({
      userInfo: ''
    })
    wx.setStorageSync('user', null)
    wx.setStorageSync('token', null)
  }
})

index.xml

<!-- 没有用户信息就绑定登录事件 -->
<button wx:if="{{!userInfo}}" bindtap="login">授权登录</button>
<view wx:else class="root">
  <image class="touxiang" src="{{userInfo.avatarUrl}}"></image>
  <text class="nicheng">{{userInfo.nickName}}</text>
  <button bindtap="loginOut">退出登录</button>
</view>

后端接口获取openid和会话密钥 session_key

session_key不应该传递到小程序,应该结合openid一期自定义一个session-id 返回给小程序来鉴定客户端小程序的登录状态
在这里插入图片描述

在这里插入图片描述!!!!!session_key则是微信服务器给开发者服务器颁发的身份凭证,开发者可以用session_key请求微信服务器其他接口来获取一些其他信息,由此可以看到,session_key不应该泄露或者下发到小程序前端。

1.控制层
/**
 * @author an
 * @version 1.0
 * @date 2021/9/19 17:34
 */
@RestController
@RequestMapping("/wechat")
public class WeiXingLoginController {

    private static final Logger logger = LoggerFactory.getLogger(WeiXingLoginController.class);
    @Autowired
    private WeiXingLoginServer weiXingLoginServer;

    @PostMapping("/login")
    public ResponseEntity<UserMsgDTO> wxLogin(@RequestBody UserMsgDTO userMsgDTO) {
        if (StringUtils.isNotBlank(userMsgDTO.getCode())) {
            logger.info("登录凭证code={}", userMsgDTO.getCode());
        }

        if (ObjectUtils.isEmpty(userMsgDTO)) {
            throw new MyException(StatusCode.ERROR, "Code is not null", "wxLogin");
        }

        UserMsgDTO userDTO = weiXingLoginServer.weChatMiNiLogin(userMsgDTO);
        logger.info("userDTO={}", userDTO);
        return ResponseEntity.ok(userDTO);
    }


}
2.表现层
**
 * @author an
 * @version 1.0
 * @date 2021/9/19 17:46
 */
@Service
public class WeiXingLoginServer {

    private static final Logger logger = LoggerFactory.getLogger(WeiXingLoginServer.class);

    @Value("${wx.appid}")
    private String appid;
    @Value("${wx.secret}")
    private String secret;
    @Value("${wx.grant_type}")
    private String grantType;
    @Value("${wx.url}")
    private String url;

    public UserMsgDTO weChatMiNiLogin(UserMsgDTO userMsgDTO) {

        Map<String, String> param = new HashMap<>();
        param.put("appid", appid);
        param.put("secret", secret);
        param.put("js_code", userMsgDTO.getCode());
        param.put("grant_type", grantType);
        //请求获取小程序服务返回的session_id
        //GET https://api.weixin.qq.com/sns/jscode2session?
        // appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
        logger.info("微信请求参数是:url={},param={}", url, param);
        String wxResult = HttpClientUtil.doGet(url, param);


        if (StringUtils.isBlank(wxResult)) {

            throw new MyException(StatusCode.ERROR, "获取不到appid");

        }
        //解析相应内容(转换成json对象)
        JSONObject jsonObject = JSONObject.parseObject(wxResult);

        String openid = jsonObject.getString("openid");//用户唯一标识
        String session_key = jsonObject.getString("session_key");获取会话密钥(session_key)
        logger.info("微信返回的结果:jsonObject={}", jsonObject);
        //
        String token = UUID.randomUUID().toString();

        RedisUtils.hPut(token, "openid", openid);
        RedisUtils.hPut(token, "session_key", session_key);
        RedisUtils.setHashKeyTime(token, 60*60, TimeUnit.SECONDS);
        logger.info("返回的token={}", token);


        UserMsgDTO userMsgDTORsp = new UserMsgDTO();
        userMsgDTORsp.setToken(token);

        return userMsgDTORsp;


    }


}

3.pojo

/**
 * @author an
 * @version 1.0
 * @date 2021/9/19 17:41
 */
@Getter
@Setter
public class UserMsgDTO implements Serializable {

    private String id;

    private String customerName;

    private String mobilePhone;

    private String avatarId;

    private String fromSource;

    private String code;

    private String nickName;

    private String avatarUrl;
    //1是男的,2是女的
    private String gender;
    //session_key
    private String session_key;
    private String token;


}

4.工具类和配置文件

坐标依赖

   <!-- httpClient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>

配置文件:

server:
  port: 19092
spring:
  application:
    name: weixing-login
  redis:
    host: 127.0.0.1
    port: 6379

wx:
  appid: "wx3*********25"  # 小程序 appId
  secret: "05465b*******a24c32"   #小程序 appSecret
  grant_type: "authorization_code"  #授权类型,此处只需填写 authorization_code
  url: "https://api.weixin.qq.com/sns/jscode2session"  # 获取appID 的请求地址

HttpClientUtil :

public class HttpClientUtil {
    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);

    //REQUEST GET
    public static String doGet(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();
        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();
            HttpGet httpGet = new HttpGet(uri);        //创建http GET请求
            response = httpclient.execute(httpGet);//执行请求
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            logger.info("REQUEST GET ExceptionError: [{}]", e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                logger.info("REQUEST GET IOExceptionError: [{}]", e.getMessage());
            }
        }
        logger.info("REQUEST GET OK, result={}", resultString);
        return resultString;
    }

    public static String doGet(String url) {
        return doGet(url, null);
    }

    //REQUEST GET
    public static String doPost(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            HttpPost httpPost = new HttpPost(url); // 创建Http Post请求
            if (param != null) { // 创建参数列表
                List<NameValuePair> paramList = new ArrayList<>();
                logger.info("paramList: {}", param);
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);// 模拟表单
            }
            response = httpClient.execute(httpPost);// 执行http请求
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");

        } catch (Exception e) {
            logger.info("REQUEST POST ExceptionError: {}", e.getMessage());
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                logger.info("REQUEST POST IOExceptionError: {}", e.getMessage());
            }
        }

        return resultString;
    }

    public static String doPost(String url) {
        return doPost(url, null);
    }

    public static String doPostJson(String url, String json) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            HttpPost httpPost = new HttpPost(url);
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            response = httpClient.execute(httpPost);// 执行http请求
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                logger.info("doPostJson IOExceptionError: {}", e.getMessage());
            }
        }
        return resultString;
    }

}

RedisUtils :


/**
 * @author an
 * @version 1.0
 * @date 2020/9/28 12:35
 */
@Component
public class RedisUtils {
    @Autowired
    private StringRedisTemplate redisTemplate;
    private static RedisUtils redisUtils;

    @PostConstruct
    public void init() {
        redisUtils = this;
        redisUtils.redisTemplate = this.redisTemplate;
    }


    /*--------------------------------------key操作-------------------------------------------*/

    /**
     * 是否存在key
     *
     * @param key
     * @return
     */
    public static Boolean hasKey(String key) {
        return redisUtils.redisTemplate.hasKey(key);
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param date
     * @return
     */
    public static Boolean expireAt(String key, Date date) {
        return redisUtils.redisTemplate.expireAt(key, date);
    }

    /**
     * 一键设置过期时间
     *
     * @param key
     * @param value
     * @param timeout (以秒为单位)
     */
    public static void set(String key, String value, long timeout) {
        redisUtils.redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }
    /*--------------------------------------String操作-------------------------------------------*/

    /**
     * 设置指定 key 的值
     *
     * @param key
     * @param value
     */
    public static void set(String key, String value) {

        redisUtils.redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 获取指定 key 的值
     *
     * @param key
     * @return
     */
    public static String get(String key) {

        return redisUtils.redisTemplate.opsForValue().get(key);
    }
    /*--------------------------------------hash操作-------------------------------------------*/

    /**
     * 获取存储在哈希表中指定字段的值
     *
     * @param key
     * @param field
     * @return
     */
    public static Object hGet(String key, String field) {
        return redisUtils.redisTemplate.opsForHash().get(key, field);
    }

    /**
     * 存储希表中指定字段的值
     *
     * @param key
     * @param hashKey
     * @param value
     */
    public static void hPut(String key, String hashKey, String value) {
        redisUtils.redisTemplate.opsForHash().put(key, hashKey, value);
    }
    /**
     * 给hash key设置过期时间
     *
     * @param key

     */
    public static void setHashKeyTime(String key, long timeout, TimeUnit unit) {
        redisUtils.redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 获取所有给定字段的值
     *
     * @param key
     * @return
     */
    public static Map<Object, Object> hGetAll(String key) {
        return redisUtils.redisTemplate.opsForHash().entries(key);
    }

    /**
     * 查看哈希表 key 中,指定的字段是否存在
     *
     * @param key
     * @param field
     * @return
     */
    public static boolean hExists(String key, String field) {
        return redisUtils.redisTemplate.opsForHash().hasKey(key, field);
    }

    /**
     * 获取哈希表中字段的数量
     *
     * @param key
     * @return
     */
    public static Long hSize(String key) {
        return redisUtils.redisTemplate.opsForHash().size(key);
    }


}

二、前端一些解释

1. success: function (res){}

res是wx.getUserProfile接口触发后返回微信服务器返回的内容

login() {
    wx.getUserProfile({
      desc: '必须授权才可以继续使用',
      success: res => {
        let user = res.userInfo
        // 把用户信息缓存到本地
        wx.setStorageSync('user', user)
        console.log("用户信息", user)
        this.setData({
          userInfo: user
        })
      },
      fail: res => {
        console.log('授权失败', res)
      }
    })
  },

参考

数据动态绑定

{{message}}

// js里如下
Page({
data: {
message: ‘我是动态绑定的数据’
}
})

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
微信小程序登录授权和手机号授权开发微信小程序时常见的功能,以下是一些优化建议: 1. 引导用户理解授权目的:在用户进行登录或手机号授权之前,向用户清晰地说明授权的目的和使用方式。提供简洁明了的说明,让用户明白为什么需要进行授权,并确保信息的安全性。 2. 简化登录流程:尽可能简化登录流程,减少用户操作。可以考虑使用一键登录或快捷登录功能,例如使用微信登录按钮,减少用户输入账号密码的步骤。 3. 提供其他登录方式:除了微信登录,还可以提供其他常见的登录方式,如手机号登录、邮箱登录或第三方账号登录。这样可以给用户更多选择,提高登录的便捷性。 4. 针对手机号授权优化: a. 自动填充手机号:在用户点击手机号授权按钮后,如果已经获取到用户手机号,则自动填充到输入框中,减少用户的手动输入。 b. 手机号验证:在获取到手机号后,对手机号进行格式验证,确保用户输入的是正确的手机号码。 c. 显示授权结果:在用户授权成功后,可以显示一个提示信息或跳转到下一步操作,让用户明确知道授权已经完成。 5. 提供明确的取消授权选项:在用户已经进行授权但后续不需要或想取消授权时,应提供一个明确的取消授权选项,让用户可以主动撤销授权。 6. 定期清理过期的授权信息:如果用户长时间未登录授权过期,应及时清理过期的授权信息,以确保用户的数据安全和准确性。 7. 保护用户隐私:在处理用户授权信息时,要严格遵守相关法规和隐私政策,确保用户数据的安全和保密性。 以上是一些微信小程序登录授权和手机号授权的优化建议,根据具体的项目需求和用户体验考虑,可以灵活调整和适应。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值