精华内容
下载资源
问答
  • flask 源码解析:session
    2021-06-10 00:17:21

    7.flask 源码解析:session

    session 简介

    在解析 session 的实现之前,我们先介绍一下 session 怎么使用。session 可以看做是在不同的请求之间保存数据的方法,因为 HTTP 是无状态的协议,但是在业务应用上我们希望知道不同请求是否是同一个人发起的。比如购物网站在用户点击进入购物车的时候,服务器需要知道是哪个用户执行了这个操作。

    在 flask 中使用 session 也很简单,只要使用 from flask import session 导入这个变量,在代码中就能直接通过读写它和 session 交互。

    from flask import Flask, session, escape, request
    
    app = Flask(__name__)
    app.secret_key = 'please-generate-a-random-secret_key'
    
    
    @app.route("/")
    def index():
        if 'username' in session:
            return 'hello, {}\n'.format(escape(session['username']))
        return 'hello, stranger\n'
    
    
    @app.route("/login", methods=['POST'])
    def login():
        session['username'] = request.form['username']
        return 'login success'
    
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=5000, debug=True)
    

    上面这段代码模拟了一个非常简单的登陆逻辑,用户访问 POST /login 来登陆,后面访问页面的时候 GET /,会返回该用户的名字。我们看一下具体的操作实例(下面的操作都是用 httpie来执行的,使用 curl 命令也能达到相同的效果):

    直接访问的话,我们可以看到返回 hello stranger

    ➜  ~ http -v http://127.0.0.1:5000/
    GET / HTTP/1.1
    Accept: */*
    Accept-Encoding: gzip, deflate
    Host: 127.0.0.1:5000
    User-Agent: HTTPie/0.8.0
    
    
    HTTP/1.0 200 OK
    Content-Length: 14
    Content-Type: text/html; charset=utf-8
    Date: Wed, 01 Mar 2017 04:22:18 GMT
    Server: Werkzeug/0.11.2 Python/2.7.10
    
    hello stranger
    

    然后我们模拟登陆请求,-v 是打印出请求,-f 是告诉服务器这是表单数据,--session=mysession 是把请求的 cookie 等信息保存到这个变量中,后面可以通过变量来指定 session:

    ➜  ~ http -v -f --session=mysession POST http://127.0.0.1:5000/login username=cizixs
    POST /login HTTP/1.1
    Accept: */*
    Accept-Encoding: gzip, deflate
    Content-Length: 15
    Content-Type: application/x-www-form-urlencoded; charset=utf-8
    Host: 127.0.0.1:5000
    User-Agent: HTTPie/0.8.0
    
    username=cizixs
    
    HTTP/1.0 200 OK
    Content-Length: 13
    Content-Type: text/html; charset=utf-8
    Date: Wed, 01 Mar 2017 04:20:54 GMT
    Server: Werkzeug/0.11.2 Python/2.7.10
    Set-Cookie: session=eyJ1c2VybmFtZSI6ImNpeml4cyJ9.C5fdpg.fqm3FTv0kYE2TuOyGF1mx2RuYQ4; HttpOnly; Path=/
    
    login success
    

    最重要的是我们看到 response 中有 Set-Cookie 的头部,cookie 的键是 session,值是一堆看起来随机的字符串。

    继续,这个时候我们用 --session=mysession 参数把这次的请求带上保存在 mysession 中的信息,登陆后访问,可以看到登陆的用户名:

    ➜  ~ http -v --session=mysession http://127.0.0.1:5000/
    GET / HTTP/1.1
    Accept: */*
    Accept-Encoding: gzip, deflate
    Cookie: session=eyJ1c2VybmFtZSI6ImNpeml4cyJ9.C5fevg.LE03yEZDWTUMQW-nNkTr1zBEhKk
    Host: 127.0.0.1:5000
    User-Agent: HTTPie/0.8.0
    
    
    HTTP/1.0 200 OK
    Content-Length: 11
    Content-Type: text/html; charset=utf-8
    Date: Wed, 01 Mar 2017 04:25:46 GMT
    Server: Werkzeug/0.11.2 Python/2.7.10
    Set-Cookie: session=eyJ1c2VybmFtZSI6ImNpeml4cyJ9.C5feyg.sfFCDIqfef4i8cvxUClUUGQNcHA; HttpOnly; Path=/
    
    hellocizixs
    

    这次注意在发送的请求中,客户端带了 Cookie 头部,上面的值保存了前一个请求的 response 给我们设置的值。

    总结一下:session 是通过在客户端设置 cookie 实现的,每次客户端发送请求的时候会附带着所有的 cookie,而里面保存着一些重要的信息(比如这里的用户信息),这样服务器端就能知道客户端的信息,然后根据这些数据做出对应的判断,就好像不同请求之间是有记忆的。

    解析

    我们知道 session 是怎么回事了,这部分就分析一下 flask 是怎么实现它的。

    请求过程

    不难想象,session 的大致解析过程是这样的:

    • 请求过来的时候,flask 会根据 cookie 信息创建出 session 变量(如果 cookie 不存在,这个变量有可能为空),保存在该请求的上下文中
    • 视图函数可以获取 session 中的信息,实现自己的逻辑处理
    • flask 会在发送 response 的时候,根据 session 的值,把它写回到 cookie 中

    注意:session 和 cookie 的转化过程中,应该考虑到安全性,不然直接使用伪造的 cookie 会是个很大的安全隐患。

    flask 上下文那篇文章中,我们知道,每次请求过来的时候,我们访问的 requestsession 变量都是 RequestContext 实例的变量。在 RequestContext.Push() 方法的最后有这么一段代码:

    self.session = self.app.open_session(self.request)
    if self.session is None:
        self.session = self.app.make_null_session()
    

    它初始化了 session 变量,保存在 RequestContext 上,这样后面就能直接通过 from flask import session 来使用它。如果没有设置 secret_key 变量, open_session 就会返回 None,这个时候会调用 make_null_session 来生成一个空的 session,这个特殊的 session 不能进行任何读写操作,不然会报异常给用户。

    我们来看看 open_session 方法:

    def open_session(self, request):
        return self.session_interface.open_session(self, request)
    

    Flask 中,所有和 session 有关的调用,都是转发到 self.session_interface 的方法调用上(这样用户就能用自定义的 session_interface 来控制 session 的使用)。而默认的 session_inerface 有默认值:

    session_interface = SecureCookieSessionInterface()
    

    后面遇到 session 有关方法解释,我们会直接讲解 SecureCookieSessionInterface 的代码实现,跳过中间的这个转发说明。

    null_session_class = NullSession
    
    def make_null_session(self, app):
        return self.null_session_class()
    
    def open_session(self, app, request):
        # 获取 session 签名的算法
        s = self.get_signing_serializer(app)
        if s is None:
            return None
    
        # 从 cookie 中获取 session 变量的值
        val = request.cookies.get(app.session_cookie_name)
        if not val:
            return self.session_class()
    
        # 因为 cookie 的数据需要验证是否有篡改,所以需要签名算法来读取里面的值
        max_age = total_seconds(app.permanent_session_lifetime)
        try:
            data = s.loads(val, max_age=max_age)
            return self.session_class(data)
        except BadSignature:
            return self.session_class()
    

    open_session 根据请求中的 cookie 来获取对应的 session 对象。之所以有 app 参数,是因为根据 app 中的安全设置(比如签名算法、secret_key)对 cookie 进行验证。

    这里有两点需要特殊说明的:签名算法是怎么工作的?session 对象到底是怎么定义的?

    session 对象

    默认的 session 对象是 SecureCookieSession,这个类就是一个基本的字典,外加一些特殊的属性,比如 permanent(flask 插件会用到这个变量)、modified(表明实例是否被更新过,如果更新过就要重新计算并设置 cookie,因为计算过程比较贵,所以如果对象没有被修改,就直接跳过)。

    class SessionMixin(object):
        def _get_permanent(self):
            return self.get('_permanent', False)
    
        def _set_permanent(self, value):
            self['_permanent'] = bool(value)
    
        #: this reflects the ``'_permanent'`` key in the dict.
        permanent = property(_get_permanent, _set_permanent)
        del _get_permanent, _set_permanent
    
        modified = True
    
    class SecureCookieSession(CallbackDict, SessionMixin):
        """Base class for sessions based on signed cookies."""
    
        def __init__(self, initial=None):
            def on_update(self):
                self.modified = True
            CallbackDict.__init__(self, initial, on_update)
            self.modified = False
    

    怎么知道实例的数据被更新过呢? SecureCookieSession 是基于 werkzeug/datastructures:CallbackDict 实现的,这个类可以指定一个函数作为 on_update 参数,每次有字典操作的时候(__setitem____delitem__clearpopitemupdatepopsetdefault)会调用这个函数。

    NOTECallbackDict 的实现很巧妙,但是并不复杂,感兴趣的可以自己参考代码。主要思路就是重载字典的一些更新操作,让它们在做原来事情的同时,额外调用一下实现保存的某个函数。

    对于开发者来说,可以把 session 简单地看成字典,所有的操作都是和字典一致的。

    签名算法

    都获取 cookie 数据的过程中,最核心的几句话是:

    s = self.get_signing_serializer(app)
    val = request.cookies.get(app.session_cookie_name)
    data = s.loads(val, max_age=max_age)
    
    return self.session_class(data)
    

    其中两句都和 s 有关,signing_serializer 保证了 cookie 和 session 的转换过程中的安全问题。如果 flask 发现请求的 cookie 被篡改了,它会直接放弃使用。

    我们继续看 get_signing_serializer 方法:

    def get_signing_serializer(self, app):
        if not app.secret_key:
            return None
        signer_kwargs = dict(
            key_derivation=self.key_derivation,
            digest_method=self.digest_method
        )
        return URLSafeTimedSerializer(app.secret_key,
            salt=self.salt,
            serializer=self.serializer,
            signer_kwargs=signer_kwargs)
    

    我们看到这里需要用到很多参数:

    • secret_key:密钥。这个是必须的,如果没有配置 secret_key 就直接使用 session会报错
    • salt:为了增强安全性而设置一个 salt 字符串(可以自行搜索“安全加盐”了解对应的原理)
    • serializer:序列算法
    • signer_kwargs:其他参数,包括摘要/hash算法(默认是 sha1)和 签名算法(默认是 hmac

    URLSafeTimedSerializeritsdangerous 库的类,主要用来进行数据验证,增加网络中数据的安全性。itsdangerours 提供了多种 Serializer,可以方便地进行类似 json 处理的数据序列化和反序列的操作。至于具体的实现,因为篇幅限制,就不解释了。

    应答过程

    flask 会在请求过来的时候自动解析 cookie 的值,把它变成 session 变量。开发在视图函数中可以使用它的值,也可以对它进行更新。最后再返回的 response 中,flask 也会自动把 session 写回到 cookie。我们来看看这部分是怎么实现的!

    之前的文章讲解了应答的过程,其中 finalize_response 方法在根据视图函数的返回生成 response 对象之后,会调用 process_response 方法进行处理。process_response 方法的最后有这样两句话:

    def process_response(self, response):
        ...
        if not self.session_interface.is_null_session(ctx.session):
            self.save_session(ctx.session, response)
        return response
    

    这里就是 session 在应答中出现的地方,思路也很简单,如果需要就调用 save_sessoin,把当前上下文中的 session 对象保存到 response 。

    save_session 的代码和 open_session 对应:

    def save_session(self, app, session, response):
            domain = self.get_cookie_domain(app)
            path = self.get_cookie_path(app)
    
            # 如果 session 变成了空字典,flask 会直接删除对应的 cookie
            if not session:
                if session.modified:
                    response.delete_cookie(app.session_cookie_name,
                                           domain=domain, path=path)
                return
    
            # 是否需要设置 cookie。如果 session 发生了变化,就一定要更新 cookie,否则用户可以 `SESSION_REFRESH_EACH_REQUEST` 变量控制是否要设置 cookie
            if not self.should_set_cookie(app, session):
                return
    
            httponly = self.get_cookie_httponly(app)
            secure = self.get_cookie_secure(app)
            expires = self.get_expiration_time(app, session)
            val = self.get_signing_serializer(app).dumps(dict(session))
            response.set_cookie(app.session_cookie_name, val,
                                expires=expires,
                                httponly=httponly,
                                domain=domain, path=path, secure=secure)
    

    这段代码也很容易理解,就是从 appsession 变量中获取所有需要的信息,然后调用 response.set_cookie 设置最后的 cookie。这样客户端就能在 cookie 中保存 session 有关的信息,以后访问的时候再次发送给服务器端,以此来实现有状态的交互。

    解密 session

    有时候在开发或者调试的过程中,需要了解 cookie 中保存的到底是什么值,可以通过手动解析它的值。sessioncookie 中的值,是一个字符串,由句号分割成三个部分。第一部分是 base64 加密的数据,第二部分是时间戳,第三部分是校验信息。

    前面两部分的内容可以通过下面的方式获取,代码也可直观,就不给出解释了:

    In [1]: from itsdangerous import *
    
    In [2]: s = 'eyJ1c2VybmFtZSI6ImNpeml4cyJ9.C5fdpg.fqm3FTv0kYE2TuOyGF1mx2RuYQ4'
    
    In [3]: data, timstamp, secret = s.split('.')
    
    In [4]: base64_decode(data)
    Out[4]: '{"username":"cizixs"}'
    
    In [5]: bytes_to_int(base64_decode(timstamp))
    Out[5]: 194502054
    
    In [7]: time.strftime('%Y-%m-%d %H:%I%S', time.localtime(194502054+EPOCH))
    Out[7]: '2017-03-01 12:1254'
    

    总结

    flask 默认提供的 session 功能还是很简单的,满足了基本的功能。但是我们看到 flask 把 session 的数据都保存在客户端的 cookie 中,这里只有用户名还好,如果有一些私密的数据(比如密码,账户余额等等),就会造成严重的安全问题。可以考虑使用 flask-session 这个三方的库,它把数据保存在服务器端(本地文件、redis、memcached),客户端只拿到一个 sessionid。

    session 主要是用来在不同的请求之间保存信息,最常见的应用就是登陆功能。虽然直接通过 session 自己也可以写出来不错的登陆功能,但是在实际的项目中可以考虑 flask-login 这个三方的插件,方便我们的开发

    更多相关内容
  • 1、预备知识 接口测试利器 HTTP Client 参数解析器 HandlerMethodArgumentResolver 解密 2、@SessionAttribute 注解 2.1、作用 用来标注在接口的参数上,参数的值来源于 session 作用域。 2.2、用法 如下代码,site...

    优质项目源码推荐

    1. 一套完整的 Spring Cloud Alibaba 视频教程

    2. 23 种设计模式实战(很全).pdf

    3. SpringBoot 学习笔记.pdf

    4. LeetCode 刷题 Java 版答案.pdf

    5. 开源一个 SpringBoot 博客系统

    大家好,我是路人,这是 SpringMVC 系列第 28 篇。

    本文将介绍 SpringMVC 中的@SessionAttribute注解。

    1、预备知识

    1. 接口测试利器 HTTP Client

    2. 参数解析器 HandlerMethodArgumentResolver 解密

    2、@SessionAttribute 注解

    2.1、作用

    用来标注在接口的参数上,参数的值来源于 session 作用域。

    2.2、用法

    如下代码,site 参数上使用了@SessionAttribute("site")注解,site 参数的值等于session.getAttribute("site")

    @ResponseBody
    public String test2(@SessionAttribute("site") String site) {
        return site;
    }

    这个注解的源码如下

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SessionAttribute {
    
     /**
      * 指定session作用域中属性的名称
      */
     @AliasFor("name")
     String value() default "";
    
     /**
      * 同value属性
      */
     @AliasFor("value")
     String name() default "";
    
     /**
      * 属性是不是必须的,如果是true,session中没有取到时,则会抛出异常
      * 此时可以将required设置为false,或者使用java8中的Option类型来修饰参数解决
      */
     boolean required() default true;
    
    }

    3、案例

    下面代码中有 2 个接口方法

    • 第一个方法 test1 中向 session 域中丢了一个 site 属性

    • 第二个方的 site 参数上标注了@SessionAttribute("site"),所以会拿到 session 中 site 的值,然后输出

    package com.javacode2018.springmvc.chat18.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    
    import javax.servlet.http.HttpSession;
    
    @Controller
    public class SessionAttributeController {
    
        @RequestMapping(value = "/sessionattribute/test1",produces = "text/html;charset=UTF-8")
        @ResponseBody
        public String test1(HttpSession session) {
            //向session中放入数据
            session.setAttribute("site",
                    "<a href='http://www.itsoku.com'>路人博客,包含了所有系列文章,阅读更方便</a>");
            //重定向
            return "session中放入了site信息!";
        }
    
        @RequestMapping(value = "/sessionattribute/test2", produces = "text/html;charset=UTF-8")
        @ResponseBody
        public String test2(@SessionAttribute("site") String site) {
            return site;
        }
    }

    下面来验证一下效果。

    浏览器中先访问第一个接口/requestattribute/test1,输出

    9a1a97c742e23190d258e42bc7cbfc07.png

    然后再访问第二个接口/requestattribute/test2,输出如下,从 session 中拿到了 site 的值

    7a2e27b9bcd84d793d22f357d00bff6c.png

    若我们调整一下接口 1 中代码,将 site 的值置为空

    request.setAttribute("site", null);

    此时再次访问接口(依次访问接口 1 和 2),第 2 个接口会报 400 错误,原因:session 域中没有找到 site 这个属性对应的值,即 session.getAttribute("site")为 null

    8587cb177464445795457a9a3a543b6d.png

    2 种解决方案

    • 方案 1:将@SessionAttribute 的 required 属性设置为 false,常用这种方式

    • 方案 2:将@SessionAttribute 标注的参数类型调整为 java8 中的 java.util.Optional 类型,上面的接口 2 的 site 参数类型可以调整为Optional<String>类型,即可解决问题

    4、@SessionAttribute 注解原理

    @SessionAttribute 注解标注的参数的值来源于org.springframework.web.servlet.mvc.method.annotation.SessionAttributeMethodArgumentResolver解析器,源码

    public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
    
     @Override
     public boolean supportsParameter(MethodParameter parameter) {
      return parameter.hasParameterAnnotation(SessionAttribute.class);
     }
    
     @Override
     protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
      SessionAttribute ann = parameter.getParameterAnnotation(SessionAttribute.class);
      Assert.state(ann != null, "No SessionAttribute annotation");
      return new NamedValueInfo(ann.name(), ann.required(), ValueConstants.DEFAULT_NONE);
     }
    
     @Override
     @Nullable
     protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) {
      return request.getAttribute(name, RequestAttributes.SCOPE_SESSION);
     }
    
     @Override
     protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException {
      throw new ServletRequestBindingException("Missing session attribute '" + name +
        "' of type " + parameter.getNestedParameterType().getSimpleName());
     }
    
    }

    5、案例代码 git 地址

    https://gitee.com/javacode2018/springmvc-series

    所有系列文章的均在此仓库中。

    6、SpringMVC 系列目录

    1. SpringMVC 系列第 1 篇:helloword

    2. SpringMVC 系列第 2 篇:@Controller、@RequestMapping

    3. SpringMVC 系列第 3 篇:异常高效的一款接口测试利器

    4. SpringMVC 系列第 4 篇:controller 常见的接收参数的方式

    5. SpringMVC 系列第 5 篇:@RequestBody 大解密,说点你不知道的

    6. SpringMVC 系列第 6 篇:上传文件的 4 种方式,你都会么?

    7. SpringMVC 系列第 7 篇:SpringMVC 返回视图常见的 5 种方式,你会几种?

    8. SpringMVC 系列第 8 篇:返回 json & 通用返回值设计

    9. SpringMVC 系列第 9 篇:SpringMVC 返回 null 是什么意思?

    10. SpringMVC 系列第 10 篇:异步处理

    11. SpringMVC 系列第 11 篇:集成静态资源

    12. SpringMVC 系列第 12 篇:拦截器

    13. SpringMVC 系列第 13 篇:统一异常处理

    14. SpringMVC 系列第 14 篇:实战篇:通用返回值 & 异常处理设计

    15. SpringMVC 系列第 15 篇:全注解的方式  &  原理解析

    16. SpringMVC 系列第 16 篇:通过源码解析 SpringMVC 处理请求的流程

    17. SpringMVC 系列第 17 篇:源码解析 SpringMVC 容器的启动过程

    18. SpringMVC 系列第 18 篇:强大的 RequestBodyAdvice 解密

    19. SpringMVC 系列第 19 篇:强大的 ResponseBodyAdvice 解密

    20. SpringMVC 系列第 20 篇:RestFull 详解

    21. SpringMVC 系列第 21 篇:接口调用过利器 RestTemplate

    22. SpringMVC 系列第 22 篇:参数解析器 HandlerMethodArgumentResolver 解密

    23. SpringMVC 系列第 23 篇:@RequestParam 用法及原理详解

    24. SpringMVC 系列第 24 篇:@RequestBody 用法及原理详解

    25. SpringMVC 系列第 25 篇:@RequestHeader 用法及原理详解

    26. SpringMVC 系列第 26 篇:@CookieValue 用法及原理详解

    27. SpringMVC 系列第 27 篇:@RequestAttribute 详解

    7、更多系列文章

    1. Spring 高手系列(共 56 篇)

    2. Java 高并发系列(共 34 篇)

    3. MySql 高手系列(共 27 篇)

    4. Maven 高手系列(共 10 篇)

    5. Mybatis 系列(共 12 篇)

    6. 聊聊 db 和缓存一致性常见的实现方式

    7. 接口幂等性这么重要,它是什么?怎么实现?

    8. 泛型,有点难度,会让很多人懵逼,那是因为你没有看这篇文章!

    8、最新资料

    1. 尚硅谷 Java 学科全套教程(总 207.77GB)

    2. 2021 最新版 Java 微服务学习线路图 + 视频

    3. 阿里技术大佬整理的《Spring 学习笔记.pdf》

    4. 阿里大佬的《MySQL 学习笔记高清.pdf》

    5. 2021 版 java 高并发常见面试题汇总.pdf

    6. Idea 快捷键大全.pdf

    展开全文
  • 微信小程序获取openid、session_key以及解密unionId、手机号的目录1、了解小程序启动时的文件加载顺序2、了解小程序自身的API3、发起网络请求与弹窗4、获取openid、session_key5、解密unionId6、解密手机号7、获取...

    1、了解小程序启动时的文件加载顺序

       在小程序编译启动时:
         先加载app.json中的一些变量定义
         再执行app.js中的一些函数(如:onLaunch: function ()函数)
         第三步是加载首页(可自己指定,如index页面)index.json中的一些变量定义
         第四步执行页面(如index页面)的index.js中的一些函数(如:onLoad: function ()函数)

    2、了解小程序自身的API

       在小程序开发过程,js 中所看到的 wx.xxx(),其本身就含有一个接口请求(请求小程序服务端的)
         只是一些请求路径和请求参数都已经内嵌了xxx里面了
         所以在 wx.xxx() 的括号中,只需编写success函数和fail函数


    注: 其中 js 中有些特定的小程序API接口需通过 按钮等 触发,如:getUserInfo、getPhoneNumber
       这实际上也是请求了一个接口,之后 才执行开发者编写的点击事件函数
    在这里插入图片描述
    在这里插入图片描述

    3、发起网络请求与弹窗

       (1)发起网络请求

    	//发起网络请求,解密获取unionId
    	
    	wx.request({
    		url: {value}
    		method: 'post',
    		header: {
    			'Content-type': 'application/json'
    		},
    		data: {
    			{key}: {value}[,
    			...]
    		},
    		success: function (result) {
    			...
    		}
    	})
    

       (2)弹窗

    	wx.showModal({
    		title: {title},
    		showCancel: false,
    		content: {content},
    		success: function (res) {
    			...
    		}
    	})
    

    4、获取openid、session_key

       在小程序编译启动时,执行app.js中函数:
         在onLaunch函数中,使用wx.login()获取登录凭证code
         并在success函数中发起网络请求,请求后端转发第三方请求 < 具体后端转发 ,可见:Java获取openid、session_key以及解密用户私密数据(UnionId或手机号)>(小程序服务器),请求auth.code2Session接口
         获取openid及session_key(如果用户有关注该小程序 同主体公众号 ,即可在 这一步获取unionId无需 经过第五部分)

           具体代码,可参考下面:
    在这里插入图片描述

    5、解密unionId


    注: 如果用户有关注了该小程序 同主体的公众号 ,即可无需这部分,可 直接通过第四部分 获得unionId

    注: 在此部分获取unionId的时候就要使用 有效 的SessionKey。要注意了是“有效”,虽然在获取SessionKey的时候有个过期时间,但是在很多场景下经常会出现超时或已经过期的情况。比如常见的一种情况是用户信息解密、手机号解密有时可以正常解密,有时候就不行。这时候基本上的问题就是 解密用的SessionKey和与加密用的SessionKey不是同一个 了。那怎么知道当前的SessionKey有没有过期,按时间来算是不行的。小程序提供 wx.checkSesstion() 这个函数,在需要 解密之前先判定一下有没有过期 ,如果 已经过期那么就先wx.login() ,这时再请求加密数据(用户信息或手机号信息),然后做解密操作的时候就可以正常的使用了。


       (1)在需要获取unionId的页面定义一个按钮(正常是在 首页 或者启动小程序时的一个 弹窗
          注: 需将 open-typebindgetuserinfo 均赋为 “getUserInfo” ;表明点击时先请求 小程序自身的getUserInfo接口
    在这里插入图片描述

       (2)在定义了按钮的 对应 js 中,编写getUserInfo接口请求后的成功函数;在其中对 开发者服务器 发起网络请求(开发者编写的 解密接口
         注: 此处所传的是 getUserInfo 获取到的 用户信息加密数据 、偏移量和 session_key ;所以解出的就是 unionId


       (3)开发者编写的解密接口 返回unionId (可见:Java获取openid、session_key以及解密用户私密数据(UnionId或手机号)

    6、解密手机号


    注: 获取用户手机号的时候就要使用 有效 的SessionKey。要注意了是“有效”,虽然在获取SessionKey的时候有个过期时间,但是在很多场景下经常会出现超时或已经过期的情况。比如常见的一种情况是用户信息解密、手机号解密有时可以正常解密,有时候就不行。这时候基本上的问题就是 解密用的SessionKey和与加密用的SessionKey不是同一个 了。那怎么知道当前的SessionKey有没有过期,按时间来算是不行的。小程序提供 wx.checkSesstion() 这个函数,在需要 解密之前先判定一下有没有过期 ,如果 已经过期那么就先wx.login() ,这时再请求加密数据(用户信息或手机号信息),然后做解密操作的时候就可以正常的使用了。

       (1)在需要获取手机号的页面定义一个按钮(大多是一个 弹窗按钮
          注: 需将 open-typebindgetphonenumber 均值定为 “getPhoneNumber” ;表明点击时先请求 小程序自身的getPhoneNumber接口


       (2)在定义了按钮的 对应 js 中,编写getPhoneNumber接口请求后的成功函数;在其中对 开发者服务器 发起网络请求(开发者编写的 解密接口

         注: 此处所传的是 getPhoneNumber 获取到的 手机号加密数据 、偏移量和 session_key ;所以解出的就是 手机号

       (3)开发者编写的解密接口 返回手机号 (可见:Java获取openid、session_key以及解密用户私密数据(UnionId或手机号)

    7、获取用户基本信息

       其实用户基本信息,就是通过小程序自身API得 getUserInfo 接口获取的
       所以,在第五部分:解密unionId ;的时候getUserInfo接口 success函数 时的 e 就包含了一些微信用户的基本信息

    8、判断是否授权过


    注:app.js 中使用 wx.getSetting() ,即可判断是否授权过

    9、SessionKey管理思路

       (1)调用wx.login()获取code,服务端根据这个code和appid和appsecret获取SessionKey(同时还有openid等数据)

       (2)把SessionKey 保存到服务器 上,一般是不在网络传输,建立自己的 SesstionID和生成的SessionKey 的对应关系

       (3)然后把生成的 SessionID 传输到小程序客户端,在小程序 本地缓存

       (4)在需要使用SessionKey的场景时先使用wx.checkSession()判定一下 有没有过期

       (5)如果没有过期就把 本地的SessionID传输到服务端 ,服务端 根据SessionID查询对应的SessionKey,进行后继的业务操作

       (6)如果本地判定 已经过期 ,那就先wx.login() 重新生成 一次code, 重新获取 一次session_key

    展开全文
  • 浏览器用Session Key解密响应消息,对消息验证后,回发消息的同时进行了第三次握手,之后就使用Session Key进行对称加密交换数据。 HTTPS需要到CA申请证书,通过加密后,进行密文传输,默认使用443端口 而HTTP则不...

    HTTP协议

    Hyper Text Transfer Protocol(超文本连接协议)简称HTTP协议。
    HTTP协议是客户/服务器模式的,用户使用的浏览器就是客户端程序。
    HTTP请求
    HTTP目前市面上多种版本共存,分别是HTTP1.0、HTTP1.1、HTTP2.0。
    HTTP1.1用得最为广泛,2.0虽然更加高级,但是1.1已经满足当前需求,且升级成本不少,所以目前还是1.1作为主流版本。

    在HTTP1.0,TCP连接默认使用短连接(Close),而从HTTP1.1开始默认使用长连接(Keep-alive)。
    短连接限制每次服务器只处理一个请求,每次处理完客户请求后,都会断开连接。
    也就是每次请求,都会进行三次握手,服务器发出响应报文和断开连接,进行四次挥手。
    无连接
    长连接则会保证连接持续一段时间后才断开,在这期间,用户可以多次请求。
    也就是三次握手后,多次进行请求(可以流水线形式,一次发送多个请求)后,再四次挥手断开连接
    长连接
    HTTP的传输流程如下

    1. 浏览器分析客户输入的URL
    2. 浏览器向DNS请求解析IP地址
    3. 根据解析出的IP地址和对应端口,建立TCP连接
    4. 发送HTTP请求报文
    5. 服务器处理请求并返回HTTP响应报文
    6. 浏览器解析渲染页面
    7. 连接结束

    HTTP报文是面向文本的,所以报文中的字段都是一些ASCII码串。
    HTTP请求报文
    HTTP请求报文
    请求方法GET和POST的比较:

    • GET请求信息在请求行中,POST请求信息在请求体中
    • GET方法符合数据库的幂等性(无论多少次对数据库的操作的得到结果都一致)和安全性(不会改变数据库的数据),POST方法不符合
    • GET可以被缓存,POST不行

    HTTP响应报文
    HTTP响应报文
    HTTP响应的状态码:

    • 1XX 指示信息 收到了请求正在处理
    • 2XX 成功 请求已接受处理
    • 3XX 重定向 完成请求还需要进一步操作
    • 4XX 客户端错误 请求有错误或无法实现
    • 5XX 服务器错误 服务器无法实现合法的请求

    常见的几种状态码:

    • 200 OK:正常返回信息
    • 400 Bad Request:客户端有语法错误,无法被服务器理解
    • 401 Unauthorized:未经授权的的请求
    • 403 Forbidden:服务器收到请求,但拒绝提供服务
    • 404 Not Found:请求资源不存在
    • 500 Internal Server Error:服务器发生不可预期错误
    • 503 Server Unavailable:服务器暂时无法处理请求,一段时候后可能回复正常

    HTTP也是无状态的协议,也就是对于事务处理是没有记忆的,如果需要处理先前的信息,必须要进行重传。
    比如最开始访问一个网站是什么样,重启浏览器后访问,仍然是一样的。
    所以存储信息就需要用到Cookie和Session。

    Cookie和Session

    由于HTTP的无状态,每次访问都是一样,但是我们需要一些个性化的定制时,就需要保存一些信息,这就用到了Cookie和Session。

    Cookie是在客户端的解决方案,是服务器发给客户端的特殊信息,将cookie信息存放在响应头中,然后存放在客户端中。
    客户端再次请求时,会把Cookie回发。
    服务器收到后,解析请求头的Cookie,生成对应内容。
    Cookie
    比如我们登录一些网站时,浏览器会询问你是否存储账户,就是将账户存入Cookie,下次访问时就不需要再次输入账号进行登录。
    这些数据都是存放在客户端(浏览器)中的,所以浏览器通常提供了管理Cookie的功能。

    而Session是在服务器端的机制,会在服务器保存信息。
    服务器在使用Session时,会解析客户端的请求,并通过Session id操作对应的Session,保存用户的状态信息。
    如果客户端是首次请求不包含Session,服务器就为客户端创建一个Session,并生成对应的Session id。

    Session的两种实现方式:

    • url回写,服务器回发的所有页面都带入Session id
      在这些页面中点击链接,都会传入Session id,但是如果是url输入访问,就不会有Session id。

    • 通过Cookie来实现,将Session id存在Cookie中
      Session id

    • Session更加安全

    • Cookie可以减少服务器负担

    HTTPS

    HTTPS
    HTTP中,即使POST方法的信息存放在请求体中,也能通过抓包来查看信息,所以HTTP并不是很安全,于是有了HTTPS

    可以看到,HTTPS比HTTP多了一层加密协议

    SSL(Security Sockets Layer,安全套接层)
    是保证通信安全和数据完整性的一种安全协议,在SSL3.0后改名TLS
    通过使用身份验证和数据加密来保证网络通信安全和数据完整性

    HTTPS利用了对称加密和非对称加密,由于非对称加密要求更多的资源,相对于对称加密的效率也低,所以只在建立连接时使用非对称加密来对对称加密的密钥进行加密。双方安全获得了对称加密的密钥后,就使用对称加密来加密数据。

    HTTPS的数据传输流程:

    • 浏览器申请和服务器建立连接
    • 服务器将公钥、网站地址、证书机构,包装成证书形式发回给浏览器
    • 浏览器验证了证书合法性之后,使用证书里的公钥Public Key,加密等下进行加密传输的对称加密的密码Session Key。发给服务器,进行第一次握手。
    • 服务器使用私钥Private Key解密后,得到Session Key,用Session Key加密响应消息回发,进行第二次握手。
    • 浏览器用Session Key解密响应消息,对消息验证后,回发消息的同时进行了第三次握手,之后就使用Session Key进行对称加密交换数据。

    HTTPS需要到CA申请证书,通过加密后,进行密文传输,默认使用443端口

    而HTTP则不需要加密,使用明文传输,默认端口为80

    SSL是有状态的,而HTTP是无状态的。

    访问一个网站的大概情况

    大致了解了TCP/IP四层协议的不同工作形式后,我们就能了解到访问一个网站大致的流程。
    比如访问www.csdn.net

    1. 首先将url交给DNS服务器进行解析,获取到要访问的csdn的ip地址
    2. 将这个ip地址,本地ip地址和子网掩码进行与运算,判断是否是子网。
    3. 将应用层的HTTP请求报文交给传输层的TCP协议。
    4. TCP协议将HTTP请求报文打包,添加TCP报头组装为TCP报文,记录了本地的源端口和要访问的目的端口等信息,交给网络层的IP协议。
    5. IP协议将TCP报文打包,添加IP包头组装为IP报文,记录了本地的ip地址和目标ip地址,然后交给数据链路层。
    6. 数据链路层再次打包IP报文,在头部添加本地网卡MAC地址和下一个网关的网卡MAC地址,将数据包广播到网关。
    7. 本地网关将数据包发送到下一个网关,该网关进行解包,了解到要访问的ip地址后,再次打包发送给下一个网关。
    8. 经过多层网关后,数据包发送到csdn的网关,交给数据链路层解包
    9. 数据链路层解包后交给网络层解包,再交给传输层解包,最后交给应用层
    10. 应用层根据HTTP请求报文,访问对应的资源,将资源数据包装为HTTP响应报文。然后通过类似的经过,将HTTP响应报文发回本地。
    展开全文
  • 详解 cookie/session

    2020-09-04 11:09:17
    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份 Cookie 什么是...
  • session、token、jwt 区别

    2022-03-31 10:01:29
    首先用户登录完成后,http 不能保存这个状态,后续的请求服务器是不知道我们是否有请求的权限的,为了解决这个问题,引入了下面几种常见的技术 session 1. 通过 session 机制,相当于服务器为客户端开辟的一个存放...
  • 今天我们讲一讲Session与Cookie的区别 1、Session对象 上一节简单介绍了Cookie,接下来简单介绍SessionSession和Cookie都是会话管理技术的一种。可能你会奇怪记住用户的信息有Cookie就够了,为什么还需要Session...
  • 常见的安全隐患 1. SQL注入 常见的案例: String query = "SELECT * FROM T_User WHERE userID='" + Request["userID"] + "'; 这个时候,只需要在传递过来的userID后面加上个: or 1=1,即可以获取T_User表中...
  • 【背景介绍】【知识剖析】【常见问题】【解决方案】【编码实战】【扩展思考】【更多讨论】【参考文献】 八个方面深度解析前端知识/技能,本篇分享的是: 【什么是session?什么是cookie?session和cookie有什么...
  • 基础加解密知识及算法介绍

    千次阅读 2021-11-22 21:18:17
    解密时只需将密文方向平移即可。 凯撒密码的输入输出如下: 安全性: 使用暴力破解,尝试26次即可破解原文信息 1.1.2 简单替换密码 26个字母之间建立映射关系,如下图为其中某种映射: 安全性: 暴力破解,需要...
  • cookie和session的加密?

    2021-04-08 08:47:45
    我现在写的前后和后台登陆大量使用了cookie和session,但是我直接就放进去了,读取也直接就读取出来了,最近听老师讲课提到cookie和session加密,我不知道现在正统做法是怎么的?是cookie和session一概都加密?还有...
  • 一篇文章弄懂cookie、session和token

    千次阅读 2018-11-05 19:33:13
    cookie存储在客户端,HTTP是无状态的,HTTP每次发出的时候会附上该域名下的cookie,从而可以给HTTP附上状态,最常见的就是登录态。 session和token session和token算是一类的,他们是两种不同的服务器的验证方式。 ...
  • cookie:浏览器在客户端电脑硬盘中开辟的一块空间,主要用来存储服务端数据(比如sessionId)。 cookie中的数据是以域名的形式进行区分的。 cookie中的数据是有过期时间的超过时间会被浏览器自动删除。 cookie中的数据...
  • session原理以及session共享

    千次阅读 2018-01-11 11:51:56
    2.session常见实现形式是会话cookie(session cookie),即未设置过期时间的cookie,这个cookie的默认生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。 3.session实现机制是当用户发起一个请求的...
  • 阅读文本大概需要3分钟。分布式Session一致性?说白了就是服务器集群Session共享的问题Session的作用?Session 是客户端与服务器通讯会话跟踪技术,服...
  • 什么是Session?cookie: 客户端浏览器的缓存;session: 服务端服务器的缓存;Session 和 Cookie类似,都是通过字典管理 key-value对。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 ...
  • 用户登录认证成功后,将用户相关数据存储到 Session 中,单体应用架构中,默认 Session 会存储在应用服务器中,并且将 Session ID 返回到客户端,存储在浏览器的 Cookie 中。 但是在分布式架构下,Session 存放于...
  • Cookie和Session详解

    万次阅读 多人点赞 2018-03-12 11:08:47
    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。本章将系统地...
  • session共享原理及实现共享

    千次阅读 2018-05-28 15:14:15
    比如用户登录邮箱后,接下来要收邮件、写邮件,总不能每次操作都让用户输入用户名和密码吧,为了解决这个问题,session的方案就被提了出来,事实上它并不是什么新技术,而且也不能脱离http协议以及任何现有的web技术...
  • 分布式session共享 集群Session共享

    千次阅读 2018-08-06 17:33:54
    最近,在工作中遇到一个问题,问题描述:一个用户在登录成功以后会把用户信息存储在session当中,这时session所在服务器为server1,那么用户在session失效之前如果再次使用app,那么可能会被路由到server2,这时问题...
  • 常见认证方法 用户名密码认证 短信验证码认证 邮箱验证码认证 扫码认证 人脸识别或者其他生物特征识别认证 1.2 授权 授权authorization,指的是用户通过身份认证后,能够访问指定的某些资源 常见授权模型—3种 ...
  • session,cookie,token 那些事儿 ?

    千次阅读 多人点赞 2021-12-14 08:25:35
    session ?cookie ?token ? 相信大家对这几个词并不陌生,不管是面试还是工作都会有涉及的,可想而知它的重要性。 网上关于 session、cookie、token 的文章有很多,每篇文章都有一些独特的见解。 在写文章之前,我...
  • session文件包含漏洞就是在用户可以控制session文件中的一部分信息,然后将这部分信息变成我们的精心构造的恶意代码,之后去包含含有我们传入恶意代码的这个session文件就可以达到攻击效果。 前言 之
  • Cookie 和 Session HTTP 协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录;Session 和 Cookie 的主要目的就是为了弥补 HTTP 的无状态特性。 ...
  • cookie、session和token区别

    千次阅读 2018-11-13 15:42:12
    cookie 和 session 众所周知,HTTP 是一个无状态协议,所以客户端每次发出请求时,下一次请求无法得知上一次请求所包含的状态数据,如何能把一个用户的状态数据关联起来呢? 比如在淘宝的某个页面中,你进行了登陆...
  • 认证和授权2.Session 与认证3.Session Fixation攻击流程如何防御4. Session 保持攻击如何防御?5.单点登录(SSO) 认证与会话管理 1.认证和授权 ​ 认证的目的是为了认出用户是谁。而授权的目的是为了决定用户能够做...
  • NodeJS 基于cookie、session的身份验证

    千次阅读 2018-11-21 11:47:07
    cookie 和 session 众所周知,HTTP 是一个无状态协议,所以客户端每次发出请求时,下一次请求无法得知上一次请求所包含的状态数据,如何能把一个用户的状态数据关联起来呢? 比如在淘宝的某个页面中,你进行了登陆...
  • 理解客户端和服务端如何通过session或者token进行登录校验的
  • 然后我们下载域名私钥配置到wireshark,发现数据包居然无法解密。是wireshark配置密钥的方法不对?但谷歌了好多文章都是说这样配置的。由于对HTTPS认识不够深,一时不知道如何入手解决。没办法,只能先了解tls这个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,471
精华内容 6,988
热门标签
关键字:

常见session解密