V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
7911364440
V2EX  ›  Java

登录最佳实践是什么?

  •  
  •   7911364440 · 2021-11-23 17:44:38 +08:00 · 7704 次点击
    这是一个创建于 1128 天前的主题,其中的信息可能已经有所发展或是发生改变。
    39 条回复    2021-11-29 11:08:20 +08:00
    psnnf
        1
    psnnf  
       2021-11-23 18:02:58 +08:00
    JWT 加个全局拦截器
    mgcnrx11
        2
    mgcnrx11  
       2021-11-23 18:11:23 +08:00   ❤️ 3
    千万别在没想清楚的时候用 JWT [手动狗头
    xuanbg
        3
    xuanbg  
       2021-11-23 18:16:13 +08:00   ❤️ 1
    不推荐 JWT ,更不推荐 Spring Security 。自己造个轮子简单实用。
    huxiaofan1223
        4
    huxiaofan1223  
       2021-11-23 21:27:51 +08:00 via iPhone
    @mgcnrx11 为啥呢
    kytrun
        5
    kytrun  
       2021-11-23 21:32:40 +08:00 via Android   ❤️ 1
    推荐 sa-token
    LeeReamond
        6
    LeeReamond  
       2021-11-23 21:38:55 +08:00   ❤️ 6
    @huxiaofan1223 jwt 只能应对它的初始设计场景,也就是令牌签发后有效期内一直有效。如果你有后续的需求,比如用户的令牌丢了,或者用户想要改密码,要让已签发的令牌失效,那么 jwt 就不能做到,需要在 jwt 基础上再加补丁。而补丁的实现,由于把存在性校验换成了不存在性校验,算法上确实可以做到一定的优化,但这种优化往往只有在特大数据量下才能表现出实际差距,考虑到开发成本,这未必值当。对于没想清楚需求的应用来说,直接保存 sessionid 是最直接也最方便的做法。
    huxiaofan1223
        7
    huxiaofan1223  
       2021-11-23 21:41:28 +08:00 via iPhone
    @LeeReamond 用 redis 和拦截器可以解决你说的这个吗?
    huxiaofan1223
        8
    huxiaofan1223  
       2021-11-23 21:42:58 +08:00 via iPhone
    @LeeReamond cookie 和 session 方便是方便,问题是对客户端不友好吧(我是前端,这是我的猜测)
    vance123
        9
    vance123  
       2021-11-24 00:25:57 +08:00
    交给第三方处理(大雾)
    当初本着能外包则外包的原则,选了 auth0.com 做用户管理,结果要学的东西更多了
    clf
        10
    clf  
       2021-11-24 00:34:17 +08:00 via iPhone
    sa token 挺好的。登录的 token 别用 jwt ,不然 token 自动续签会很麻烦。
    gargar
        11
    gargar  
       2021-11-24 00:35:01 +08:00
    @vance123 哈哈,跟上云一样,以为不用自己维护机房了,结果要学的东西一点都不少
    jinliming2
        12
    jinliming2  
       2021-11-24 01:07:51 +08:00
    @huxiaofan1223 客户端问题也不大,正常的网络请求库都有 cookie jar ,自动管理 cookie 的
    chendy
        13
    chendy  
       2021-11-24 08:25:34 +08:00
    一个 ThreadLocal 存当前用户(和权限) + 一个拦截器存进去+删掉,完事
    可以参考安全框架的设计,但是不建议用,因为麻烦。。。
    JamesMackerel
        14
    JamesMackerel  
       2021-11-24 09:00:28 +08:00 via iPhone
    一个服务:数据库里存密码,用 bcrypt 存储密码。
    多个服务:用 sso ,可以用 oauth 或者 cas 。

    登录验证的 filter 可以抄一下 java-cas-client 里的 AuthenticationFilter ,获取当前用户信息的操作可以抄 AssertionHolder
    banlifeather4
        15
    banlifeather4  
       2021-11-24 09:10:13 +08:00
    @LeeReamond

    1. 用户令牌丢了?
    回答:这个问题....


    2. 用户改密码后,使已签发的令牌失效
    回答:用户密码后,可以再生成新的 token , 你可以选择返回前端, 让他更新请求令牌,或让用户重新登录(取决于你的需求设计)
    sujin190
        16
    sujin190  
       2021-11-24 09:14:19 +08:00
    @banlifeather4 #15 我猜改密码这个的意思是用户登录了两台设备,在其中一台设备上改密码了,无法把另外一台踢下线,否则就得查询用户状态了,这样还不如用 session 了
    sujin190
        17
    sujin190  
       2021-11-24 09:16:17 +08:00
    @huxiaofan1223 #8 因为好多不知道 cookiejar 的,所以各种传 cookie 和 session 对客户端不友好也真是。。
    banlifeather4
        18
    banlifeather4  
       2021-11-24 09:20:57 +08:00
    @sujin190

    EMMM , 我们有用到 WS , 所以一些关键流程, 会推送消息到前端, 让前端处理一些流程;
    就像我们使用大厂的 APP 一样, 会弹出来, 密码已修改,需要重新登录
    masterclock
        19
    masterclock  
       2021-11-24 09:22:03 +08:00
    1. 不登录
    2. 用 Keycloak 之类的东西,总之保证请求到自己的服务的时候,鉴权啥的都已经完成了,不需要关心了
    LeeReamond
        20
    LeeReamond  
       2021-11-24 09:22:44 +08:00
    @banlifeather4 很正常的需求,不知道你想问什么,比如手机作为唯一身份认证终端的时代 ,丢手机当然不是 0 概率事件,其他认证方式同理,你这问题属于想的太多做得太少,做了就遇到这种需求了。
    sujin190
        21
    sujin190  
       2021-11-24 09:30:24 +08:00
    @banlifeather4 #18 你这个并没有解决问题吧,且不说最简单的设备不在线就走不通,毕竟不是大厂设备在线率不能比,再者用户改密码大多可能有异常登录之类的,既然异常登录了,那说不定 WS 就没用了呢,所以你这个方案是无所谓的正常改密码能正常踢下线,必须要改密码的异常情况恰恰可能反而踢不下线了,反着来么
    mosakashaka
        22
    mosakashaka  
       2021-11-24 09:34:47 +08:00   ❤️ 1
    jwt 踢用户做点改造不就得了,加个自定义属性。
    spring security 没明白为什么不用,而要自己造轮子。。
    securityCoding
        23
    securityCoding  
       2021-11-24 09:48:44 +08:00
    登录态拦截在网关做,业务中从上下文获取属性即可根本不要关注登录态.省时省力省心
    timethinker
        24
    timethinker  
       2021-11-24 10:03:28 +08:00   ❤️ 7
    登录其实就是认证,认证与授权是两个相对独立的过程。

    认证解决的问题:你是谁?一般只是简单的通过标识(用户名)和凭证(密码)来确定身份。确定身份以后,认证系统一般会发放一个 Token (令牌)或者直接绑定身份信息并关联当前的 sessionid (会话,通过 cookie 传递)。

    授权解决的问题:在已认证的情况下,也就是我知道你是谁的情况下,你能做什么?

    关于密码:不要使用明文,后端也不要接收明文(固然有 TLS ),前端可以使用 BCrypt 慢哈希生成密码摘要,不要在后端使用慢哈希。后端生成(注册)/获取(登录)动态盐值,与前端发过来的摘要结合再次哈希一遍得到最终的摘要信息。

    关于 JWT:JWT 只是作为令牌的一种承载形式,它不可伪造,不可篡改,表达了签发此令牌的真实意图,但是不要将敏感信息放进去。好处固然有,例如完全可以在不跟签发者通讯的情况下对其进行验证(签名以及有效期),但是涉及到撤销的情况下,就必须记录每一个令牌的状态( jti 是每一个令牌的 ID ),可以建立令牌黑名单机制,虽然丧失了完全的无状态好处,但是验证这个比较轻量级。

    我想说的就是可以根据场景结合混合使用不同的技术,关于安全这一块,不要自己去发明东西,大胆的使用经过时间检验的通用方法,具体如何实现只是细节问题(比如框架,亦或是自己手写),但是在流程上,概念上一定要有清晰的认知。
    shuimugan
        25
    shuimugan  
       2021-11-24 13:08:00 +08:00 via Android
    如果项目前后端分离得很彻底,可以把原来存在 cookie 的 session id 丢到 local storage ,请求的时候取出来追加到 header 上,可以从根本上杜绝 csrf 攻击,还能让扫描器或者等保服务提供商的初级安全人员一脸懵逼
    Casbin
        26
    Casbin  
       2021-11-24 13:12:27 +08:00
    可以试试 Casdoor: https://v2ex.com/t/803669 ,支持与 Spring-Boot 项目集成: https://github.com/casdoor/casdoor-spring-boot-example
    ihwbunny
        27
    ihwbunny  
       2021-11-24 13:17:42 +08:00
    为啥没人提多设备验证
    danieladu
        28
    danieladu  
       2021-11-24 16:06:09 +08:00
    yangzzzzzz
        29
    yangzzzzzz  
       2021-11-24 16:18:05 +08:00
    简单点 jwt 单 token ,复杂点双 token 。
    MonikaCeng
        30
    MonikaCeng  
       2021-11-24 17:31:46 +08:00 via Android
    我之前做短信登录,安全策略是,同 ip 发短信超过 5 条该 ip 需要验证码。当日短信发送总量超过 1000 条,当日所有人需要验证码
    getoffworkontime
        31
    getoffworkontime  
       2021-11-24 19:04:04 +08:00
    直接用阿里云的 API 网关
    leeg810312
        32
    leeg810312  
       2021-11-24 23:11:45 +08:00 via Android
    jwt 那么多好处为什么不用? jwt 跨域方便,横向扩展方便,代码什么都不用改,cookie 和 session 可以吗? jwt 没有提供吊销,但也容易补这个特性。生成时缓存一份,校验前去缓存查一下,吊销时把缓存里的删了就好了。jwt 的好处也用了,缺点也弥补了。
    joApioVVx4M4X6Rf
        33
    joApioVVx4M4X6Rf  
       2021-11-25 09:49:28 +08:00
    @yangzzzzzz 求教双 token 是啥啊?是 access_token 和 refresh_token 吗
    ArmstrongLiu
        34
    ArmstrongLiu  
       2021-11-25 10:41:27 +08:00
    @qwe520liao #24 关于“关于密码” 这块有两个疑问:

    1. Bcrypt 哈希算法每次生成的哈希值都是不同的(即使是相同的密码),这样后端是如何校验密码的正确性的呢?

    2. 前后端交互时不使用明文的原因是什么?如果出现别人通过抓包或者请求拦截获取到密码或者密码摘要,这二者造成的后果是不是都是一样的?因为不管是用密码或者是密码摘要模拟请求,后端的密码验证都是可以通过的。
    timethinker
        35
    timethinker  
       2021-11-25 13:03:36 +08:00
    @ArmstrongLiu
    1 、前端 Bcrypt 是可能的,我们需要的就是把“慢”这个过程放到客户端内,代码细节可以看一下我刚创建的这个测试,需要一个固定的盐值: https://jsfiddle.net/4zdw1jab/

    2 、不使用明文不仅仅只是说为了传输上的考虑,明文就是“烫手山芋”,只要生成摘要的过程是安全可靠的,其实我们根本就不需要明文。其他的顾虑包括但不限于意外的日志输出或者其他的安全漏洞,所以彻底的做法就是后端根本就不接收明文。当然这一条只是作为一个建议,如果手动模拟注册请求给后端接口发送的就是明文,那么当然也可以模拟登录用之前的明文,关于这种“非法”注册的用户,当然也就排除在正常的产品流程之外了。
    ZeroDu
        36
    ZeroDu  
       2021-11-25 15:38:09 +08:00
    自己写个拦截器 + uuid +redis 无烦恼。
    yangzzzzzz
        37
    yangzzzzzz  
       2021-11-25 16:09:18 +08:00
    @v2exblog 是的
    ArmstrongLiu
        38
    ArmstrongLiu  
       2021-11-26 11:05:15 +08:00
    @qwe520liao 如果前端使用固定盐值,那应该没有问题。我之前使用 python ( passlib.hash )进行测试时一直没有使用盐值,所以它每次都自动生成 salt ,就导致每次的 hash 值不同。
    letitbesqzr
        39
    letitbesqzr  
       2021-11-29 11:08:19 +08:00
    sa-token 好用
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3603 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 04:23 · PVG 12:23 · LAX 20:23 · JFK 23:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.