基于redis的小程序登录实现方法流程分析

这张图是小程序的登录流程解析:

小程序登陆授权流程:

在小程序端调用wx.login()获取code,由于我是做后端开发的这边不做赘述,直接贴上代码了.有兴趣的直接去官方文档看下,链接放这里: wx.login()

wx.login({
 success (res) {
 if (res.code) {
 //发起网络请求
 wx.request({
 url: 'https://test.com/onLogin',
 data: {
 code: res.code
 }
 })
 } else {
 console.log('登录失败!' + res.errMsg)
 }
 }
})

小程序前端登录后会获取code,调用自己的开发者服务接口,调用个get请求:

GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

需要得四个参数:
appid:小程序appid
secret: 小程序密钥
js_code: 刚才获取的code
grant_type:‘authorization_code' //这个是固定的

如果不出意外的话,微信接口服务器会返回四个参数:

详情可以看下官方文档:jscode2session

下面附上我的代码:

@AuthIgnore
 @RequestMapping("/login")
 @ResponseBody
 public ResponseBean openId(@RequestParam(value = "code", required = true) String code,
  @RequestParam(value = "avatarUrl") String avatarUrl,
  @RequestParam(value = "city") String city,
  @RequestParam(value = "country") String country,
  @RequestParam(value = "gender") String gender,
  @RequestParam(value = "language") String language,
  @RequestParam(value = "nickName") String nickName,
  @RequestParam(value = "province") String province,
  HttpServletRequest request) { // 小程序端获取的CODE
 ResponseBean responseBean = new ResponseBean();
 try {
 boolean check = (StringUtils.isEmpty(code)) ? true : false;
 if (check) {
 responseBean = new ResponseBean(false, UnicomResponseEnums.NO_CODE);
 return responseBean;
 }
 //将获取的用户数据存入数据库;
 Map<String, Object> msgs = new HashMap<>();
 msgs.put("appid", appId);
 msgs.put("secret", secret);
 msgs.put("js_code", code);
 msgs.put("grant_type", "authorization_code");
 // java的网络请求,返回字符串
 String data = HttpUtils.get(msgs, Constants.JSCODE2SESSION);
 logger.info("======> " + data);
 String openId = JSONObject.parseObject(data).getString("openid");
 String session_key = JSONObject.parseObject(data).getString("session_key");
 String unionid = JSONObject.parseObject(data).getString("unionid");
 String errcode = JSONObject.parseObject(data).getString("errcode");
 String errmsg = JSONObject.parseObject(data).getString("errmsg");

 JSONObject json = new JSONObject();
 int userId = -1;

 if (!StringUtils.isBlank(openId)) {
 Users user = userService.selectUserByOpenId(openId);
 if (user == null) {
  //新建一个用户信息
  Users newUser = new Users();
  newUser.setOpenid(openId);
  newUser.setArea(city);
  newUser.setSex(Integer.parseInt(gender));
  newUser.setNickName(nickName);
  newUser.setCreateTime(new Date());
  newUser.setStatus(0);//初始
  if (!StringUtils.isBlank(unionid)) {
  newUser.setUnionid(unionid);
  }
  userService.instert(newUser);
  userId = newUser.getId();
 } else {
  userId = user.getId();
 }
 json.put("userId", userId);
 }
 if (!StringUtils.isBlank(session_key) && !StringUtils.isBlank(openId)) {
 //这段可不用redis存,直接返回session_key也可以
 String userAgent = request.getHeader("user-agent");
 String sessionid = tokenService.generateToken(userAgent, session_key);
 //将session_key存入redis
 redisUtil.setex(sessionid, session_key + "###" + userId, Constants.SESSION_KEY_EX);
 json.put("token", sessionid);

 responseBean = new ResponseBean(true, json);
 } else {
 responseBean = new ResponseBean<>(false, null, errmsg);
 }
 return responseBean;
 } catch (Exception e) {
 e.printStackTrace();
 responseBean = new ResponseBean(false, UnicomResponseEnums.JSCODE2SESSION_ERRO);
 return responseBean;
 }
 }

解析:

这边我的登录获取的session_key出于安全性考虑没有直接在前端传输,而是存到了redis里面给到前端session_key的token传输,
而且session_key的销毁时间是20分钟,时间内可以重复获取用户数据.
如果只是简单使用或者对安全性要求不严的话可以直接传session_key到前端保存.

session_key的作用:

校验用户信息(wx.getUserInfo(OBJECT)返回的signature);
解密(wx.getUserInfo(OBJECT)返回的encryptedData);

按照官方的说法,wx.checksession是用来检查 wx.login(OBJECT) 的时效性,判断登录是否过期;
疑惑的是(openid,unionid )都是用户唯一标识,不会因为wx.login(OBJECT)的过期而改变,所以要是没有使用wx.getUserInfo(OBJECT)获得的用户信息,确实没必要使用wx.checksession()来检查wx.login(OBJECT) 是否过期;
如果使用了wx.getUserInfo(OBJECT)获得的用户信息,还是有必要使用wx.checksession()来检查wx.login(OBJECT) 是否过期的,因为用户有可能修改了头像、昵称、城市,省份等信息,可以通过检查wx.login(OBJECT) 是否过期来更新着些信息;

小程序的登录状态维护本质就是维护session_key的时效性

这边附上我的HttpUtils工具代码,如果只要用get的话可以复制部分:

如果是直

/**
 * HttpUtils工具类
 *
 * @author
 */
public class HttpUtils {
 /**
 * 请求方式:post
 */
 public static String POST = "post";
 /**
 * 编码格式:utf-8
 */
 private static final String CHARSET_UTF_8 = "UTF-8";
 /**
 * 报文头部json
 */
 private static final String APPLICATION_JSON = "application/json";
 /**
 * 请求超时时间
 */
 private static final int CONNECT_TIMEOUT = 60 * 1000;
 /**
 * 传输超时时间
 */
 private static final int SO_TIMEOUT = 60 * 1000;
 /**
 * 日志
 */
 private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);
 /**
 * @param protocol
 * @param url
 * @param paraMap
 * @return
 * @throws Exception
 */
 public static String doPost(String protocol, String url,
  Map<String, Object> paraMap) throws Exception {
 CloseableHttpClient httpClient = null;
 CloseableHttpResponse resp = null;
 String rtnValue = null;
 try {
 if (protocol.equals("http")) {
 httpClient = HttpClients.createDefault();
 } else {
 // 获取https安全客户端
 httpClient = HttpUtils.getHttpsClient();
 }
 HttpPost httpPost = new HttpPost(url);
 List<NameValuePair> list = msgs2valuePairs(paraMap);
// List<NameValuePair> list = new ArrayList<NameValuePair>();
// if (null != paraMap &&paraMap.size() > 0) {
// for (Entry<String, Object> entry : paraMap.entrySet()) {
//  list.add(new BasicNameValuePair(entry.getKey(), entry
//  .getValue().toString()));
// }
// }
 RequestConfig requestConfig = RequestConfig.custom()
  .setSocketTimeout(SO_TIMEOUT)
  .setConnectTimeout(CONNECT_TIMEOUT).build();// 设置请求和传输超时时间
 httpPost.setConfig(requestConfig);
 httpPost.setEntity(new UrlEncodedFormEntity(list, CHARSET_UTF_8));
 resp = httpClient.execute(httpPost);
 rtnValue = EntityUtils.toString(resp.getEntity(), CHARSET_UTF_8);
 } catch (Exception e) {
 logger.error(e.getMessage());
 throw e;
 } finally {
 if (null != resp) {
 resp.close();
 }
 if (null != httpClient) {
 httpClient.close();
 }
 }
 return rtnValue;
 }
 /**
 * 获取https,单向验证
 *
 * @return
 * @throws Exception
 */
 public static CloseableHttpClient getHttpsClient() throws Exception {
 try {
 TrustManager[] trustManagers = new TrustManager[]{new X509TrustManager() {
 public void checkClientTrusted(
  X509Certificate[] paramArrayOfX509Certificate,
  String paramString) throws CertificateException {
 }
 public void checkServerTrusted(
  X509Certificate[] paramArrayOfX509Certificate,
  String paramString) throws CertificateException {
 }
 public X509Certificate[] getAcceptedIssuers() {
  return null;
 }
 }};
 SSLContext sslContext = SSLContext
  .getInstance(SSLConnectionSocketFactory.TLS);
 sslContext.init(new KeyManager[0], trustManagers,
  new SecureRandom());
 SSLContext.setDefault(sslContext);
 sslContext.init(null, trustManagers, null);
 SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(
  sslContext,
  SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
 HttpClientBuilder clientBuilder = HttpClients.custom()
  .setSSLSocketFactory(connectionSocketFactory);
 clientBuilder.setRedirectStrategy(new LaxRedirectStrategy());
 CloseableHttpClient httpClient = clientBuilder.build();
 return httpClient;
 } catch (Exception e) {
 throw new Exception("http client 远程连接失败", e);
 }
 }
 /**
 * post请求
 *
 * @param msgs
 * @param url
 * @return
 * @throws ClientProtocolException
 * @throws UnknownHostException
 * @throws IOException
 */
 public static String post(Map<String, Object> msgs, String url)
 throws ClientProtocolException, UnknownHostException, IOException {
 CloseableHttpClient httpClient = HttpClients.createDefault();
 try {
 HttpPost request = new HttpPost(url);
 List<NameValuePair> valuePairs = msgs2valuePairs(msgs);
// List<NameValuePair> valuePairs = new ArrayList<NameValuePair>();
// if (null != msgs) {
// for (Entry<String, Object> entry : msgs.entrySet()) {
//  if (entry.getValue() != null) {
//  valuePairs.add(new BasicNameValuePair(entry.getKey(),
//  entry.getValue().toString()));
//  }
// }
// }
 request.setEntity(new UrlEncodedFormEntity(valuePairs, CHARSET_UTF_8));
 CloseableHttpResponse resp = httpClient.execute(request);
 return EntityUtils.toString(resp.getEntity(), CHARSET_UTF_8);
 } finally {
 httpClient.close();
 }
 }
 /**
 * post请求
 *
 * @param msgs
 * @param url
 * @return
 * @throws ClientProtocolException
 * @throws UnknownHostException
 * @throws IOException
 */
 public static byte[] postGetByte(Map<String, Object> msgs, String url)
 throws ClientProtocolException, UnknownHostException, IOException {
 CloseableHttpClient httpClient = HttpClients.createDefault();
 InputStream inputStream = null;
 byte[] data = null;
 try {
 HttpPost request = new HttpPost(url);
 List<NameValuePair> valuePairs = msgs2valuePairs(msgs);
// List<NameValuePair> valuePairs = new ArrayList<NameValuePair>();
// if (null != msgs) {
// for (Entry<String, Object> entry : msgs.entrySet()) {
//  if (entry.getValue() != null) {
//  valuePairs.add(new BasicNameValuePair(entry.getKey(),
//  entry.getValue().toString()));
//  }
// }
// }
 request.setEntity(new UrlEncodedFormEntity(valuePairs, CHARSET_UTF_8));
 CloseableHttpResponse response = httpClient.execute(request);
 try {
 // 获取相应实体
 HttpEntity entity = response.getEntity();
 if (entity != null) {
  inputStream = entity.getContent();
  data = readInputStream(inputStream);
 }
 return data;
 } catch (Exception e) {
 e.printStackTrace();
 } finally {
 httpClient.close();
 return null;
 }
 } finally {
 httpClient.close();
 }
 }
 /** 将流 保存为数据数组
 * @param inStream
 * @return
 * @throws Exception
 */
 public static byte[] readInputStream(InputStream inStream) throws Exception {
 ByteArrayOutputStream outStream = new ByteArrayOutputStream();
 // 创建一个Buffer字符串
 byte[] buffer = new byte[1024];
 // 每次读取的字符串长度,如果为-1,代表全部读取完毕
 int len = 0;
 // 使用一个输入流从buffer里把数据读取出来
 while ((len = inStream.read(buffer)) != -1) {
 // 用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
 outStream.write(buffer, 0, len);
 }
 // 关闭输入流
 inStream.close();
 // 把outStream里的数据写入内存
 return outStream.toByteArray();
 }
 /**
 * get请求
 *
 * @param msgs
 * @param url
 * @return
 * @throws ClientProtocolException
 * @throws UnknownHostException
 * @throws IOException
 */
 public static String get(Map<String, Object> msgs, String url)
 throws ClientProtocolException, UnknownHostException, IOException {
 CloseableHttpClient httpClient = HttpClients.createDefault();
 try {
 List<NameValuePair> valuePairs = msgs2valuePairs(msgs);
// List<NameValuePair> valuePairs = new ArrayList<NameValuePair>();
// if (null != msgs) {
// for (Entry<String, Object> entry : msgs.entrySet()) {
//  if (entry.getValue() != null) {
//  valuePairs.add(new BasicNameValuePair(entry.getKey(),
//  entry.getValue().toString()));
//  }
// }
// }
 // EntityUtils.toString(new UrlEncodedFormEntity(valuePairs),
 // CHARSET);
 url = url + "?" + URLEncodedUtils.format(valuePairs, CHARSET_UTF_8);
 HttpGet request = new HttpGet(url);
 CloseableHttpResponse resp = httpClient.execute(request);
 return EntityUtils.toString(resp.getEntity(), CHARSET_UTF_8);
 } finally {
 httpClient.close();
 }
 }
 public static <T> T post(Map<String, Object> msgs, String url,
  Class<T> clazz) throws ClientProtocolException,
 UnknownHostException, IOException {
 String json = HttpUtils.post(msgs, url);
 T t = JSON.parseObject(json, clazz);
 return t;
 }
 public static <T> T get(Map<String, Object> msgs, String url, Class<T> clazz)
 throws ClientProtocolException, UnknownHostException, IOException {
 String json = HttpUtils.get(msgs, url);
 T t = JSON.parseObject(json, clazz);
 return t;
 }
 public static String postWithJson(Map<String, Object> msgs, String url)
 throws ClientProtocolException, IOException {
 CloseableHttpClient httpClient = HttpClients.createDefault();
 try {
 String jsonParam = JSON.toJSONString(msgs);
 HttpPost post = new HttpPost(url);
 post.setHeader("Content-Type", APPLICATION_JSON);
 post.setEntity(new StringEntity(jsonParam, CHARSET_UTF_8));
 CloseableHttpResponse response = httpClient.execute(post);
 return new String(EntityUtils.toString(response.getEntity()).getBytes("iso8859-1"), CHARSET_UTF_8);
 } finally {
 httpClient.close();
 }
 }
 public static <T> T postWithJson(Map<String, Object> msgs, String url, Class<T> clazz) throws ClientProtocolException,
 UnknownHostException, IOException {
 String json = HttpUtils.postWithJson(msgs, url);
 T t = JSON.parseObject(json, clazz);
 return t;
 }
 public static List<NameValuePair> msgs2valuePairs(Map<String, Object> msgs) {
 List<NameValuePair> valuePairs = new ArrayList<NameValuePair>();
 if (null != msgs) {
 for (Entry<String, Object> entry : msgs.entrySet()) {
 if (entry.getValue() != null) {
  valuePairs.add(new BasicNameValuePair(entry.getKey(),
  entry.getValue().toString()));
 }
 }
 }
 return valuePairs;
 }
}

接传session_key到前端的,下面的可以不用看了.
如果是redis存的sesssion_key的token的话,这边附上登陆的时候的token转换为session_key.

自定义拦截器注解:

import java.lang.annotation.*;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthIgnore {
}

拦截器部分代码:

 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 AuthIgnore annotation;
 if(handler instanceof HandlerMethod) {
 annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthIgnore.class);
 }else{
 return true;
 }
 //如果有@AuthIgnore注解,则不验证token
 if(annotation != null){
 return true;
 }
// //获取微信access_token;
// if(!redisUtil.exists(Constants.ACCESS_TOKEN)){
// Map<String, Object> msgs = new HashMap<>();
// msgs.put("appid",appId);
// msgs.put("secret",secret);
// msgs.put("grant_type","client_credential");
// String data = HttpUtils.get(msgs,Constants.GETACCESSTOKEN); // java的网络请求,返回字符串
// String errcode= JSONObject.parseObject(data).getString("errcode");
// String errmsg= JSONObject.parseObject(data).getString("errmsg");
// if(StringUtils.isBlank(errcode)){
// //存储access_token
// String access_token= JSONObject.parseObject(data).getString("access_token");
// long expires_in=Long.parseLong(JSONObject.parseObject(data).getString("expires_in"));
// redisUtil.setex("ACCESS_TOKEN",access_token, expires_in);
// }else{
// //异常返回数据拦截,返回json数据
// response.setCharacterEncoding("UTF-8");
// response.setContentType("application/json; charset=utf-8");
// PrintWriter out = response.getWriter();
// ResponseBean<Object> responseBean=new ResponseBean<>(false,null, errmsg);
// out = response.getWriter();
// out.append(JSON.toJSON(responseBean).toString());
// return false;
// }
// }
 //获取用户凭证
 String token = request.getHeader(Constants.USER_TOKEN);
// if(StringUtils.isBlank(token)){
// token = request.getParameter(Constants.USER_TOKEN);
// }
// if(StringUtils.isBlank(token)){
// Object obj = request.getAttribute(Constants.USER_TOKEN);
// if(null!=obj){
// token=obj.toString();
// }
// }
// //token凭证为空
// if(StringUtils.isBlank(token)){
// //token不存在拦截,返回json数据
// response.setCharacterEncoding("UTF-8");
// response.setContentType("application/json; charset=utf-8");
// PrintWriter out = response.getWriter();
// try{
// ResponseBean<Object> responseBean=new ResponseBean<>(false,null, UnicomResponseEnums.TOKEN_EMPTY);
// out = response.getWriter();
// out.append(JSON.toJSON(responseBean).toString());
// return false;
// }
// catch (Exception e) {
// e.printStackTrace();
// response.sendError(500);
// return false;
// }
// }
 if(token==null||!redisUtil.exists(token)){
 //用户未登录,返回json数据
 response.setCharacterEncoding("UTF-8");
 response.setContentType("application/json; charset=utf-8");
 PrintWriter out = response.getWriter();
 try{
 ResponseBean<Object> responseBean=new ResponseBean<>(false,null, UnicomResponseEnums.DIS_LOGIN);
 out = response.getWriter();
 out.append(JSON.toJSON(responseBean).toString());
 return false;
 }
 catch (Exception e) {
 e.printStackTrace();
 response.sendError(500);
 return false;
 }
 }
 tokenManager.refreshUserToken(token);
 return true;
 }
}

过滤器配置:

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
 @Override
 public void addInterceptors(InterceptorRegistry registry) {
 registry.addInterceptor(authorizationInterceptor())
 .addPathPatterns("/**")// 拦截所有请求,通过判断是否有 @AuthIgnore注解 决定是否需要登录
 .excludePathPatterns("/user/login");//排除登录
 }
 @Bean
 public AuthorizationInterceptor authorizationInterceptor() {
 return new AuthorizationInterceptor();
 }
}

token管理:

@Service
public class TokenManager {
 @Resource
 private RedisUtil redisUtil;
 //生成token(格式为token:设备-加密的用户名-时间-六位随机数)
 public String generateToken(String userAgentStr, String username) {
 StringBuilder token = new StringBuilder("token:");
 //设备
 UserAgent userAgent = UserAgent.parseUserAgentString(userAgentStr);
 if (userAgent.getOperatingSystem().isMobileDevice()) {
 token.append("MOBILE-");
 } else {
 token.append("PC-");
 }
 //加密的用户名
 token.append(MD5Utils.MD5Encode(username) + "-");
 //时间
 token.append(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + "-");
 //六位随机字符串
 token.append(UUID.randomUUID().toString());
 System.out.println("token-->" + token.toString());
 return token.toString();
 }
 /**
 * 登录用户,创建token
 *
 * @param token
 */
 //把token存到redis中
 public void save(String token, Users user) {
 if (token.startsWith("token:PC")) {
 redisUtil.setex(token,JSON.toJSONString(user), Constants.TOKEN_EX);
 } else {
 redisUtil.setex(token,JSON.toJSONString(user), Constants.TOKEN_EX);
 }
 }
 /**
 * 刷新用户
 *
 * @param token
 */
 public void refreshUserToken(String token) {
 if (redisUtil.exists(token)) {
 String value=redisUtil.get(token);
 redisUtil.setex(token, value, Constants.TOKEN_EX);
 }
 }
 /**
 * 用户退出登陆
 *
 * @param token
 */
 public void loginOut(String token) {
 redisUtil.remove(token);
 }
 /**
 * 获取用户信息
 *
 * @param token
 * @return
 */
 public Users getUserInfoByToken(String token) {
 if (redisUtil.exists(token)) {
 String jsonString = redisUtil.get(token);
 Users user =JSONObject.parseObject(jsonString, Users.class);
 return user;
 }
 return null;
 }
}

redis工具类:

@Component
public class RedisUtil {
 @Resource
 private RedisTemplate<String, String> redisTemplate;
 public void set(String key, String value) {
 ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
 valueOperations.set(key, value);
 }
 public void setex(String key, String value, long seconds) {
 ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
 valueOperations.set(key, value, seconds,TimeUnit.SECONDS);
 }
 public Boolean exists(String key) {
 return redisTemplate.hasKey(key);
 }
 public void remove(String key) {
 redisTemplate.delete(key);
 }
 public String get(String key) {
 ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
 return valueOperations.get(key);
 }
}

最后redis要实现序列化,序列化最终的目的是为了对象可以跨平台存储,和进行网络传输。而我们进行跨平台存储和网络传输的方式就是IO,而我们的IO支持的数据格式就是字节数组。本质上存储和网络传输 都需要经过 把一个对象状态保存成一种跨平台识别的字节格式,然后其他的平台才可以通过字节信息解析还原对象信息。

@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig {
 @Bean
 @ConditionalOnMissingBean(name = "redisTemplate")
 public RedisTemplate<Object, Object> redisTemplate(
 RedisConnectionFactory redisConnectionFactory) {
 RedisTemplate<Object, Object> template = new RedisTemplate<>();
 //使用fastjson序列化
 FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
 // value值的序列化采用fastJsonRedisSerializer
 template.setValueSerializer(fastJsonRedisSerializer);
 template.setHashValueSerializer(fastJsonRedisSerializer);
 // key的序列化采用StringRedisSerializer
 template.setKeySerializer(new StringRedisSerializer());
 template.setHashKeySerializer(new StringRedisSerializer());
 template.setConnectionFactory(redisConnectionFactory);
 return template;
 }
 @Bean
 @ConditionalOnMissingBean(StringRedisTemplate.class)
 public StringRedisTemplate stringRedisTemplate(
 RedisConnectionFactory redisConnectionFactory) {
 StringRedisTemplate template = new StringRedisTemplate();
 template.setConnectionFactory(redisConnectionFactory);
 return template;
 }
}

作者:gigass
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

总结

到此这篇关于基于redis的小程序登录实现的文章就介绍到这了,更多相关redis小程序登录内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Redis开启远程登录连接

    今天使用jedis客户端api连接远程连接redis的时候,一直报错,如下: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused: connect at redis.clients.jedis.Connection.connect(Connection.java:164) at redis.clients.jedis.BinaryClient.

  • php+redis实现注册、删除、编辑、分页、登录、关注等功能示例

    本文实例讲述了php+redis实现注册.删除.编辑.分页.登录.关注等功能.分享给大家供大家参考,具体如下: 主要界面 连接redis redis.php <?php //实例化 $redis = new Redis(); //连接服务器 $a=$redis->connect("localhost",6379); //var_dump($a); //授权 $redis->auth("107lab"); 注册界面 add.php <form

  • 使用redis管理用户登录会话的方法

    登录和cookie缓存 对于用来登录的cookie,有两种常见的方法可以将登录信息存储在cookie里面:一种是签名(signed)cookie,另一种是令牌(token)cookie. 签名cookie通常会存储用户名,可能还有用户ID.用户最后一次成功登陆的时间,以及网站觉得有用的其他任何信息.除了用户的相关信息外,签名cookie还包含一个签名,服务器可以使用这个签名来验证发送的信息是否未经改动(比如将cookie中的登录用户名改成另一个客户). 令牌cookie会在cookie里面存储一

  • 详解Redis使用认证密码登录

    Redis默认配置是不需要密码认证的,也就是说只要连接的Redis服务器的host和port正确,就可以连接使用.这在安全性上会有一定的问题,所以需要启用Redis的认证密码,增加Redis服务器的安全性. 1. 修改配置文件 Redis的配置文件默认在/etc/redis.conf,找到如下行: #requirepass foobared 去掉前面的注释,并修改为所需要的密码: requirepass myPassword (其中myPassword就是要设置的密码) 2. 重启Redis 如

  • redis-cli 使用密码登录的实例

    首先进入redis-cli控制台 #./redis-cli 输入auth +空格+ 刚才设置的密码 成功! 以上这篇redis-cli 使用密码登录的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • 实例详解Spring Boot实战之Redis缓存登录验证码

    本章简单介绍redis的配置及使用方法,本文示例代码在前面代码的基础上进行修改添加,实现了使用redis进行缓存验证码,以及校验验证码的过程. 1.添加依赖库(添加redis库,以及第三方的验证码库) <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency&

  • 基于redis的小程序登录实现方法流程分析

    这张图是小程序的登录流程解析: 小程序登陆授权流程: 在小程序端调用wx.login()获取code,由于我是做后端开发的这边不做赘述,直接贴上代码了.有兴趣的直接去官方文档看下,链接放这里: wx.login() wx.login({ success (res) { if (res.code) { //发起网络请求 wx.request({ url: 'https://test.com/onLogin', data: { code: res.code } }) } else { console

  • 关于微信小程序登录的那些事

    前言 最近团队在开发一款小程序,都是新手,一边看文档,一边开发.在开发中会遇到各种问题,今天把小程序登录这块的流程整理下,做个记录. 小程序的登录跟平时自己APP这种登录验证还不太一样,多了一个角色,那就是微信服务器. 根据微信官方提供的登录流程时序图可以清楚的了解小程序登录需要多少个步骤,下面我们来总结下: 小程序启动,通过wx.login()获取code 开发者服务器需要提供一个登录的接口,参数就是小程序获取的code 登录接口收到code后,调用微信提供的接口进行code的验证 得到验证结

  • Java中基于Shiro,JWT实现微信小程序登录完整例子及实现过程

    小程序官方流程图如下,官方地址 : https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html : 本文是对接微信小程序自定义登录的一个完整例子实现 ,技术栈为 : SpringBoot+Shiro+JWT+JPA+Redis. 如果对该例子比较感兴趣或者觉得言语表达比较啰嗦,可查看完整的项目地址 : https://github.com/EalenXie/shiro-jwt-applet

  • 小程序登录态管理的方法示例

    所谓的登录态其实就是客户端发送请求的时候携带的token(通常叫做令牌),当用户输入账号密码,验证成功之后,服务端生成一个token传递给客户端,客户端在后续的请求中携带这个token,服务器进行校验,校验成功则处理客户端的请求,校验失败则要求客户端重新去登陆. 在web项目中,我们通常使用session来管理这一过程. 客户端首次访问请求的时候,服务端返回一个sessionId作为cookie给客户端,往后客户端每次请求都带上这个cookie与服务端进行通信,当执行完登陆操作以后,服务端将用户

  • 微信小程序登录方法之授权登陆及获取微信用户手机号

    目录 先看一下小程序的登陆流程 第一步, 调用微信登陆方法 wx.login() 获取临时登录凭证code ,并回传到开发者服务器. ​​​​​第二步,获取用户信息,点击事件,获取用户授权,用户同意后然后返回信息 ​​第三步,获取用户手机号 结束语 先看一下小程序的登陆流程 使用说明注意: 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID . 用户在微信开放平台帐号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台帐号) 和 会话密钥 session_k

  • 微信小程序登录态控制深入分析

    微信小程序登录态控制深入分析 最近微信小程序终于开放了个人注册,我当然不能浪费这个炫技的好机会,"菲麦日程"小程序正在全力推进中,尽请期待~~ 在登录态控制中,摸索尝试了小一阵子,特此分享 一.微信建议的登录态控制 说明: 1)小程序内通过wx.login接口获得code 2)将code传入后台,后台对微信服务器发起一个https请求换取openid.session_key 3)后台生成一个自身的3rd_session(以此为key值保持openid和session_key),返回给前

  • 微信小程序 登录实例详解

    微信小程序登录 一. 小程序不支持cookie会话 1. 通过传递与检验3rd_session来保持会话 2. 3rd_session可以执行'`head -n 80 /dev/urandom | tr -dc A-Za-z0-9 | head -c 168`该命令生成 3. 使用Redis或者数据库存储session 4. 生成的3rd_session发送给客户端,写入storage 5. 客户端的每次请求必须带上3rd_session 二.加密数据解码 1. $iv,$code是被加密过的数

  • 微信小程序登录换取token的教程

    前言: 这次主要是介绍些业务逻辑,技术点倒是没有多少.不过在开发中,优秀的编程思路同样是非常值得学习的. 最近小程序可以说在开发届狠狠的火了一把.微信小程序可以开发游戏,腾讯率先带头,做出了一个跳一跳也是点爆朋友圈.所谓落后就要挨打,那么今天就开始学习小程序的一些小知识吧(本文基于十年磨一剑的tp5) 目录: 微信登录换取token的流程 如何将code变成openid和session_key 抛出错误异常和派发令牌 一:微信登录换取token的流程 多说无益,直接上图 小程序获取token.p

  • java实现微信小程序登录态维护的示例代码

    相信不少喜欢开发的朋友都已经知道微信小程序是个什么物种了,楼主也是从小程序内测期间就开始关注,并且也写过几个已经上线的微信小程序.但是基本上都是写的纯前端,最近楼主从后端到前端写一个完整的小程序项目,中间碰到了一些问题,楼主会找一些个人觉得有学习价值的点不定时的拿出来跟大家分享,希望对你有一些帮助. 本次就从最基本的微信小程序登录态维护开始吧.小程序官方api文档里面有对登录态的一个完整的解释,并且有相关的代码.想看详情,可以出门右转:https://mp.weixin.qq.com/debug

  • 微信小程序登录数据解密及状态维持实例详解

    本文实例讲述了微信小程序登录数据解密及状态维持.分享给大家供大家参考,具体如下: 学习过小程序的朋友应该知道,在小程序中是不支持cookie的,借助小程序中的缓存我们也可以存储一些信息,但是对于一些比较重要的信息,我们需要通过登录状态维持来保存,同时,为了安全起见,用户的敏感信息,也是需要加密在网络上传输的. 前台,service.封装了http请求,同时封装了getSession(通过code获取服务器生成的session).getUserInfo(获取用户信息).getDecryptionD

随机推荐