精华内容
下载资源
问答
  • JWT token流程

    2019-10-18 17:00:26
    在前后分离场景下,越来越多的项目使用token作为接口的安全机制,APP端或者WEB端(使用VUE、REACTJS等构建)使用token与后端接口交互,以达到安全的目的。本文结合stackover以及本身项目实践,试图总结出一个通用的...

    业务场景

    在前后分离场景下,越来越多的项目使用token作为接口的安全机制,APP端或者WEB端(使用VUE、REACTJS等构建)使用token与后端接口交互,以达到安全的目的。本文结合stackover以及本身项目实践,试图总结出一个通用的,可落地的方案。

    基本思路

    • 单个token
    1. token(A)过期设置为15分钟
    2. 前端发起请求,后端验证token(A)是否过期;如果过期,前端发起刷新token请求,后端设置已再次授权标记为true,请求成功
    3. 前端发起请求,后端验证再次授权标记,如果已经再次授权,则拒绝刷新token的请求,请求成功
    4. 如果前端每隔72小时,必须重新登录,后端检查用户最后一次登录日期,如超过72小时,则拒绝刷新token的请求,请求失败
    • 授权token加上刷新token

    用户仅登录一次,用户改变密码,则废除token,重新登录

    1.0实现

    1.登录成功,返回access_token和refresh_token,客户端缓存此两种token;
    2.使用access_token请求接口资源,成功则调用成功;如果token超时,客户端
    携带refresh_token调用中间件接口获取新的access_token;
    3.中间件接受刷新token的请求后,检查refresh_token是否过期。
    如过期,拒绝刷新,客户端收到该状态后,跳转到登录页;
    如未过期,生成新的access_token和refresh_token并返回给客户端(如有可能,让旧的refresh_token失效),客户端携带新的access_token重新调用上面的资源接口。
    4.客户端退出登录或修改密码后,调用中间件注销旧的token(使access_token和refresh_token失效),同时清空客户端的access_token和refresh_toke。

    后端表
    id user_id client_id client_secret refresh_token expire_in create_date del_flag

    2.0实现

    场景: access_token访问资源 refresh_token授权访问 设置固定时间X必须重新登录

    1.登录成功,后台jwt生成access_token(jwt有效期30分钟)和refresh_token(jwt有效期15天),并缓存到redis(hash-key为token,sub-key为手机号,value为设备唯一编号(根据手机号码,可以人工废除全部token,也可以根据sub-key,废除部分设备的token。),设置过期时间为1个月,保证最终所有token都能删除),返回后,客户端缓存此两种token;
    2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果token超时,中间件删除access_token(废除);客户端再次携带refresh_token调用中间件接口获取新的access_token;
    3.中间件接受刷新token的请求后,检查refresh_token是否过期。
    如过期,拒绝刷新,删除refresh_token(废除); 客户端收到该状态后,跳转到登录页;
    如未过期,检查缓存中是否有refresh_token(是否被废除),如果有,则生成新的access_token并返回给客户端,客户端接着携带新的access_token重新调用上面的资源接口。
    4.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token和refresh_token(废除)),同时清空客户端侧的access_token和refresh_toke。
    5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。
    6.以上3刷新access_token可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(拒绝的场景:失效,长时间未登录,频繁刷新)

    2.0 变动
    1.登录
    2.登录拦截器
    3.增加刷新access_token接口
    4.退出登录
    5.修改密码

    3.0实现

    场景:自动续期 长时间未使用需重新登录

    1.登录成功,后台jwt生成access_token(jwt有效期30分钟),并缓存到redis(hash-key为access_token,sub-key为手机号,value为设备唯一编号(根据手机号码,可以人工废除全部token),设置access_token过期时间为7天,保证最终所有token都能删除),返回后,客户端缓存此token;

    2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果token超时,中间件删除access_token(废除),同时生成新的access_token并返回。客户端收到新的access_token,
    再次请求接口资源。

    3.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token(废除)),同时清空客户端侧的access_token。

    4.以上2 可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(拒绝的场景:长时间未登录,频繁刷新)

    5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。

    3.0 变动

    1.登录
    2.登录拦截器
    3.退出登录
    4.修改密码

    1.3 场景:token过期重新登录 长时间未使用需重新登录

    1.登录成功,后台jwt生成access_token(jwt有效期7天),并缓存到redis,key为 "user_id:access_token",value为access_token(根据用户id,可以人工废除指定用户全部token),设置缓存过期时间为7天,保证最终所有token都能删除,请求返回后,客户端缓存此access_token;

    2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果token超时,中间件删除access_token(废除),同时生成新的access_token并返回。客户端收到新的access_token,
    再次请求接口资源。

    3.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token(废除)),同时清空客户端侧的access_token。

    4.以上2 可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(拒绝的场景:长时间未登录,频繁刷新)

    5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。

    1.3 变动

    1.登录
    2.登录拦截器
    3.退出登录
    4.修改密码

    解决方案

    2.0 场景: access_token访问资源 refresh_token授权访问 设置固定时间X必须重新登录

    1.登录成功,后台jwt生成access_token(jwt有效期30分钟)和refresh_token(jwt有效期15天),并缓

    存到redis(hash-key为token,sub-key为手机号,value为设备唯一编号(根据手机号码,可以人工废除全

    部token,也可以根据sub-key,废除部分设备的token。),设置过期时间为1个月,保证最终所有token都

    能删除),返回后,客户端缓存此两种token;

    2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果

    token超时,中间件删除access_token(废除);客户端再次携带refresh_token调用中间件接口获取新的

    access_token;

    3.中间件接受刷新token的请求后,检查refresh_token是否过期。

    如过期,拒绝刷新,删除refresh_token(废除); 客户端收到该状态后,跳转到登录页;

    如未过期,检查缓存中是否有refresh_token(是否被废除),如果有,则生成新的access_token并返回给

    客户端,客户端接着携带新的access_token重新调用上面的资源接口。

    4.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token和refresh_token(

    废除)),同时清空客户端侧的access_token和refresh_toke。

    5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。

    6.以上3刷新access_token可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(

    拒绝的场景:失效,长时间未登录,频繁刷新)

    2.0 变动

    1.登录

    2.登录拦截器

    3.增加刷新access_token接口

    4.退出登录

    5.修改密码

    3.0 场景:自动续期 长时间未使用需重新登录

    1.登录成功,后台jwt生成access_token(jwt有效期30分钟),并缓存到redis(hash-key为

    access_token,sub-key为手机号,value为设备唯一编号(根据手机号码,可以人工废除全部token,也可以

    根据sub-key,废除部分设备的token。),设置access_token过期时间为1个月,保证最终所有token都能删

    除),返回后,客户端缓存此token;

    2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果

    token超时,中间件删除access_token(废除),同时生成新的access_token并返回。客户端收到新的

    access_token,

    再次请求接口资源。

    3.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token(废除)),同时清

    空客户端侧的access_token。

    4.以上2 可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(拒绝的场景:长

    时间未登录,频繁刷新)

    5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。

    3.0 变动

    1.登录

    2.登录拦截器

    3.退出登录

    4.修改密码

    4.0 场景:token过期重新登录 长时间未使用需重新登录

    1.登录成功,后台jwt生成access_token(jwt有效期7天),并缓存到redis,key为

    "user_id:access_token" + 用户id,value为access_token(根据用户id,可以人工废除指定用户全部

    token),设置缓存过期时间为7天,保证最终所有token都能删除,请求返回后,客户端缓存此

    access_token;

    2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果

    token超时,中间件删除access_token(废除),同时生成新的access_token并返回。客户端收到新的

    access_token,

    再次请求接口资源。

    3.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token(废除)),同时清

    空客户端侧的access_token。

    4.以上2 可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(拒绝的场景:长

    时间未登录,频繁刷新)

    5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。

    4.0 变动

    1.登录

    2.登录拦截器

    3.退出登录

    4.修改密码

    最终实现

    后端

    1. 在登录接口中 如果校验账号密码成功 则根据用户id和用户类型创建jwt token(有效期设置为-1,即永不过期),得到A
    2. 更新登录日期(当前时间new Date()即可)(业务上可选),得到B
    3. 在redis中缓存key为ACCESS_TOKEN:userId:A(加上A是为了防止用户多个客户端登录 造成token覆盖),value为B的毫秒数(转换成字符串类型),过期时间为7天(7 * 24 * 60 * 60)
    4. 在登录结果中返回json格式为{"result":"success","token": A}
    5. 用户在接口请求header中携带token进行登录,后端在所有接口前置拦截器进行拦截,作用是解析token 拿到userId和用户类型(用户调用业务接口只需要传token即可), 如果解析失败(抛出SignatureException),则返回json(code = 0 ,info= Token验证不通过, errorCode = '1001'); 此外如果解析成功,验证redis中key为ACCESS_TOKEN:userId:A 是否存在 如果不存在 则返回json(code = 0 ,info= 会话过期请重新登录, errorCode = '1002'); 如果缓存key存在,则自动续7天超时时间(value不变),实现频繁登录用户免登陆。
    6. 把userId和用户类型放入request参数中 接口方法中可以直接拿到登录用户信息
    7. 如果是修改密码或退出登录 则废除access_tokens(删除key)

    前端(VUE)

    1. 用户登录成功,则把username存入cookie中,key为loginUser;把token存入cookie中,key为accessToken 把token存入Vuex全局状态中
    2. 进入首页
    展开全文
  • 重写自带的用户认证和token流程token应用流程:Django提供内置的用户认证功能。为何要自己写认证如何使用的jwt自带的验证视图在前端登录ajax请求重写jwt的返回内容JWT如何返回用户信息或者修改信息serializers.py写...


    官方文档:https://yiyibooks.cn/xx/Django_1.11.6/topics/auth/index.html

    token应用流程:

    • 初次登录:用户初次登录,输入用户名密码
    • 密码验证:服务器从数据库取出用户名和密码进行验证
    • 生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT
    • 返还JWT:服务器的HTTP RESPONSE中将JWT返还
    • 带JWT的请求:以后客户端发起请求,HTTP REQUEST HEADER中的Authorizatio字段都要有值,为JWT,注意JWT后带一个空格

    Django提供内置的用户认证功能。

    在进行用户登陆验证的时候,如果是自己写代码,就必须要先查询数据库,看用户输入的用户名是否存在于数据库中;
    如果用户存在于数据库中,然后再验证用户输入的密码,这样一来就要自己编写大量的代码。

    事实上,Django已经提供了内置的用户认证功能。

    为何要自己写认证

    有时候我们需要用到邮箱或者手机登录而不只是用户名,所以需要自己重写功能,在utils文件夹里创建一个文件utils.py里面写:

    #当前文件夹里面,定义的是自定义的认证系统
    from django.contrib.auth.backends import ModelBackend
    import re
    from user import models
    
    '''Django自带的认证系统
        
        def authenticate(self, request, username=None, password=None, **kwargs):
            if username is None:
                username = kwargs.get(UserModel.USERNAME_FIELD)
            try:
                user = UserModel._default_manager.get_by_natural_key(username)
            except UserModel.DoesNotExist:
                # Run the default password hasher once to reduce the timing
                # difference between an existing and a non-existing user (#20760).
                UserModel().set_password(password)
            else:
                if user.check_password(password) and self.user_can_authenticate(user):
                    return user'''
    
    '''当前的类,是用来定义的认证方法'''
    class UserPhoneEmailAuthBackend(ModelBackend):
    
    
        def authenticate(self, request, username=None, password=None, **kwargs):
    
            '''
    
            :param request:
            :param username:可能是手机号码/邮箱/用户名
            :param password:
            :param kwargs:
            :return:
            '''
    
            #1. todo 不管是用户或者邮箱或者手机号码,第一件事获取对象
            try:
                #todo 先通过正则,判断出手机号码/用户名/邮箱
                if re.match(r'^1[\d]{10}$',username):
                    user = models.User.objects.get(phone=username)
                    print('111111111111111111eeeeeeeeerrrrrrrrrrrrrrrrr')
                elif re.match('^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$',username):
                    user = models.User.objects.get(email=username)
                else:
                    user = models.User.objects.get(username=username)
    
            except models.User.DoesNotExist:
                user = None
    
    
                # todo 拿到user之后进行校验
            if user is not None and user.check_password(password):
                return user
    
    
    

    如何使用的jwt自带的验证视图

    直接在对应的urls.py里配置即可

    from rest_framework_jwt.views import obtain_jwt_token
    
    urlpatterns = [
        url(r'^login/',obtain_jwt_token),
    ]
    
    

    在前端登录ajax请求

    通过ajax请求发送用户名和密码。验证成功后会得到token。
    然后把token存到localStorage,这个是固定存储网页关闭了也存在,在设置.py里可以设置过期时间。

    $(function () {
        $('#llogin').click(function () {
            //获取用户名和密码
            //用户名
            var username = $('#lusername').val();
            var password = $('#lpassword').val();
    
            //拼接json数据向后端传递数据
            var data = {
                'username':username,
                'password':password
            };
            //将对象转成json数据
            data_json = JSON.stringify(data)
            //发送
    
            $.ajax({
                url:'http://127.0.0.1:8000/user/login/',
                type:'POST',
                data:data_json,
                contentType:'application/json',
                dataType:'json',
                success:function (data) {
                    alert(data)
                    console.log(data);
                    //清空token
                    localStorage.clear();
                    //储存token
                    localStorage.token=data['token'];
                    //返回到前端
    
                    console.log( '返回到前端');
                    console.log( localStorage.token)
    
                },
                error:function (data){
                    alert('请求失败')
                }
    
            })
        })
    });
    

    重写jwt的返回内容

    因为默认使用的返回只有token,我们需要更多地内容比如username和id,当然也可以前端解析base64来实现,这里使用后端重写来返回更多内容。
    还是在utils文件夹里的utils.py写一个函数:

    def jwt_response_username_userid_token(token,user=None,request=None):
        '''
    
        JWT登入验证成功之后 ,自定义处理返回数据
        :param token:
        :param user:
        :param request:
        :return:
        '''
    
        data = {
            'token':token,
            'username':user.username,
            'user_id':user.id
        }
        return data
    

    然后在自己的设置文件里配置,我的是dev.py,添加这个配置路径也就是第二个键值对

    # 设置过期时间和jwt返回值
    JWT_AUTH = {
            #jwt过期时间
            #'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=60),
            'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
            #配置自定义jwt返回内容
            'JWT_RESPONSE_PAYLOAD_HANDLER':'shanghui.utils.utils.jwt_response_username_userid_token'
    }
    

    这时候前端访问即可得到:

    Object {user_id: 21, token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1N…ExIn0.6IEeAsMgg_qRCivw0ErmLqvYmlvVF7ckvpxjNmdfUGs", username: "1111"}
    
    

    JWT如何返回用户信息或者修改信息

    serializers.py写一个序列化器

    fields里面填需要的值就行,我在models添加了一些值,便于修改

    class LodinUserInfoSerializer(serializers.ModelSerializer):
        ''''email
        为了偷懒直接用
        '''
        class Meta:
            model = models.User
            fields = ('id','username','phone','email')
    

    view.py设置指定模型(重要)

    这个导的是RetrieveUpdateAPIView,可以实现get和put请求

    class LodinUserInfoView( RetrieveAPIView):
        '''用户信息返回给前端'''
    
        # 1.指定序列化器
        serializer_class = serializers.LodinUserInfoSerializer
        # todo 进行权限的指定
        #两种都可以
        permission_classes = (IsAuthenticated,)
        #permission_classes = [IsAuthenticated]
    
        # 2.指定单个模型
        def get_object(self):
            print('=================================')
            print(self.request.user)
            return self.request.user
    

    js根据JWT的值发送get请求获取信息

    这是用户信息界面,get请求需要添加请求头设置:

    • ‘Authorization’: 'JWT ’ + token
      来访问,如果有效就能取到用户信息,并且设置了当前页面的标签值
    $(function () {
        token = localStorage.token
        // alert(token)
        //get()等价于ajax({})
    
        $.ajax({
            url:'http://127.0.0.1:8000/user/userinfo/',
            method:'GET',
            headers:{
                //‘JWT ’里面必须带空格
                'Authorization':'JWT '+ token
            },
            success:function (data) {
                // alert('ok');
                console.log(data);
    
                console.log( '返回到前端');
                console.log( localStorage.token);
                //替换用户名
                email = data['email'];
                username = data['username'];
                phone = data['phone'];
                console.log(email,phone,username);
                $('#uusername').html(username);
                $('#uusername1').val(username);
                $('#uemail').val(email);
                $('#uphone').val( phone)
    
            },
            error:function (data) {
                console.log(data);
                console.log('error');
                console.log(data['status']);
                if (data['status']==401){
                    location.href = 'http://127.0.0.1:8080/templates/login.html'
                }
                // alert('失败');
            }
    
        });
    
       
    });
    

    js里根据JWT的值发送PUT请求

    其实和GET是一样的,要注意添加请求头即可

    $('#btn').click(function () {
    
             $.ajax({
            url:'http://127.0.0.1:8000/user/email/',
    
            headers:{
                //‘JWT ’里面必须带空格
                'Authorization':'JWT '+ token
            },
                 type:'PUT',
                 id:'',
                 //email:'1246081324@qq.com',
                 data:{
                    _method:'PUT',
                     "email":'1246081324@qq.com'
                 },
                 dataType:'json',
            success:function (data) {
                alert('ok');
                console.log(data);
    
    
                console.log( '返回到前端');
                console.log( localStorage.token);
                替换用户名
                email = data['email'];
                username = data['username'];
                phone = data['phone'];
                console.log(email,phone,username);
                $('#uusername').html(username);
                $('#uusername1').val(username);
                $('#uemail').val(email);
                $('#uphone').val( phone)
    
            },
            error:function (data) {
                console.log(data);
                console.log('error');
                console.log(data['status']);
                if (data['status']==401){
                    location.href = 'http://127.0.0.1:8080/templates/login.html'
                }
                // alert('失败');
    
            $.ajax({
            url:'http://127.0.0.1:8000/user/email/',
            method:'PUT',
            headers:{
                //‘JWT ’里面必须带空格
                'Authorization':'JWT '+ token
            },
            success:function (data) {
                // alert('ok');
                console.log(data);
    
                console.log( '返回到前端');
                console.log( localStorage.token);
                替换用户名
                email = data['email'];
                username = data['username'];
                phone = data['phone'];
                console.log(email,phone,username);
                $('#uusername').html(username);
                $('#uusername1').val(username);
                $('#uemail').val(email);
                $('#uphone').val( phone)
    
            },
            error:function (data) {
                console.log(data);
                console.log('error');
                console.log(data['status']);
                if (data['status']==401){
                    location.href = 'http://127.0.0.1:8080/templates/login.html'
                }
                // alert('失败');
    
    
            }
    
        })
        });
    
    展开全文
  • token流程

    2017-12-09 10:04:00
    转载于:https://www.cnblogs.com/mrszhou/p/8010657.html

     

    转载于:https://www.cnblogs.com/mrszhou/p/8010657.html

    展开全文
  • EOS发行Token流程

    千次阅读 2018-05-08 18:12:37
    下图是一个EOS下一个简单的发行token合约的代码片段create 是创建token的结构transfer是转帐的结构issue是发行的结构使用:eosiocpp命令编译源代码代码编译结果主要有两个文件:.abi和.wast文件,向EOS公链上部署...

    下图是一个EOS下一个简单的发行token合约的代码片段

    create 是创建token的结构

    transfer是转帐的结构

    issue是发行的结构


    使用:eosiocpp命令编译源代码

    代码编译结果主要有两个文件:.abi和.wast文件,向EOS公链上部署智能合约需要这两个文件。

    下面截图和文字说明解释一下合约部署和一系列操作流程

    step1、首先执行下面两条命令把链启动起来

    cd ~/eos/build/programs/nodeos

    ./nodeos 

         

        

    step2、执行下面命令到cleos目录下

    cd ~/eos/build/programs/cleos

    执行下面图中的命令进行必要的初始设置,命令和执行结果




    step3、执行下图中的命令,导如私钥,eosio超级账户创建一个账户currency


    step4、eosio账户发行10亿EOS token


    step5、读取 eosio账户的EOS token 余额

    ./cleos get currency balance eos eosio

    step6、使用超级账户 eosio 创建一个账户 eos.ck,并转账 1000.0000 EOS 查看账户余额



    以上是对EOS token转账查询的操作,下面正式进入对合约token的操作

    step7、部署currency,下面是部署智能合约,创建token,发行token,转帐的命令和执等结果截图








    展开全文
  • jwt token 流程讲解

    千次阅读 2018-04-09 17:58:56
    重写WebSecurityConfigurerAdapter的配置项,为自己需要的进行配置配置不需要携带token进行认证的路径认证请求对登陆和刷新token放行,可以自定义添加更多不需要携带token的路径然后对其他的路径都要求携带toke...
  • 1、获取服务商Accesstoken(每10分钟企业微信会推送一次,两个小时后过期) 2、根据suitid、accesstoken、第三方企业corpid、第三方...https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token.... ) ...
  • Ebay 获取用户访问token 流程

    千次阅读 2018-04-10 15:15:46
    Step 1. ... 创建 application access keys ; 有两种, 一种是应用到沙箱环境, 一种是应用到线上环境。...然后 获取 token 填写完资料,就可以获得 可以得到用户授权码的网页, 我们可以得到...
  • 官方时序图如下: ...图里其实说的很清楚了,清理下流程: 1.前端调用wx.login()获取code值 2.前端通过调用wx.getUserInfo获取iv、rawData、signature、encryptedData等加密数据,传递...
  • token应用流程: 内置的认证登陆 为何要自己写认证 如何使用的jwt自带的验证视图 在前端登录ajax请求 重写jwt的返回内容 JWT如何返回用户信息或者修改信息 serializers.py写一个序列化器 view.py设置指定模型(重要...
  • 提示:只有认证过的订阅号或者服务号才能获取access_token。 1.app微信登录第一步是,app调起来微信客户端,通过app端的配置,引入一个微信类库, 2.授权成功后,微信会返回你一个code。 将APP_ID替换成你在微信...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,258
精华内容 1,703
关键字:

token流程