加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – JWT身份验证:如何实现注销?

发布时间:2020-12-15 00:07:36 所属栏目:Java 来源:网络整理
导读:我为我的 Spring启动应用程序实现了JWT身份验证.总的来说,它的工作原理如下: 客户端将用户名,密码发送到登录端点. 服务器检查提供的凭据是否有效. 如果不是,则会返回错误 如果是,它将返回一个令牌,该令牌实际包含 客户端会在每个将来的请求中发送该令牌 问
我为我的 Spring启动应用程序实现了JWT身份验证.总的来说,它的工作原理如下:

>客户端将用户名,密码发送到登录端点.
>服务器检查提供的凭据是否有效.
>如果不是,则会返回错误
>如果是,它将返回一个令牌,该令牌实际包含
>客户端会在每个将来的请求中发送该令牌

问题是,我们应该如何实施注销?

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.util.Date;

class TokenAuthenticationService {
    static final long EXPIRATIONTIME = 864_000_000; // 10 days
    static final String SECRET = "ThisIsASecret";
    static final String TOKEN_PREFIX = "Bearer";
    static final String HEADER_STRING = "Authorization";

    static void addAuthentication(HttpServletResponse res,String username) {
        String JWT = Jwts
                .builder()
                .setSubject(username)
                .setExpiration(
                        new Date(System.currentTimeMillis() + EXPIRATIONTIME))
                .signWith(SignatureAlgorithm.HS512,SECRET).compact();
        res.addHeader(HEADER_STRING,TOKEN_PREFIX + " " + JWT);
    }

    static Authentication getAuthentication(HttpServletRequest request,UserDetailsService customUserDetailsService) {
        String token = request.getHeader(HEADER_STRING);
        if (token != null) {
            // parse the token.
            Claims claims = Jwts.parser().setSigningKey(SECRET)
                    .parseClaimsJws(token.replace(TOKEN_PREFIX,"")).getBody();
            String userName = claims.getSubject();
            Date expirationTime = claims.getExpiration();
            if (expirationTime.compareTo(new Date()) < 0) {
                return null;
            }
            UserDetails user = customUserDetailsService.loadUserByUsername(userName);
            return user != null ? new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword(),user.getAuthorities()) : null;
        }
        return null;
    }
}

jWTLoginFilter类使用addAuthentication在登录时发送身份验证代码,’getAuthentication由jWTAuthenticationFilter使用,用于过滤对端点的所有请求.

这里的最佳做法是什么?

解决方法

我不认为这里有最好的做法.我想这取决于你正在构建的应用程序和它的要求.

JWT的好处是它们是无国籍的.您无需查询数据库即可验证令牌.当您希望减少数据库的负载时这很好,但是当您想要使现有的非过期令牌无效时,这是很好的.

可能的解决方案:

>将JWT存储在数据库中.您可以检查哪些令牌有效以及哪些令牌已被撤销,但这在我看来完全违背了使用JWT的目的.>从客户端删除令牌.这将阻止客户端进行经过身份验证的请求,但如果令牌仍然有效且其他人可以访问它,则仍可以使用该令牌.这引出了我的下一点.>令牌生命周期短.让令牌快速到期.根据应用,可能是几分钟或半小时.当客户端删除其令牌时,会有一个很短的时间窗口仍然可以使用它.从客户端删除令牌并具有短令牌生存期不需要对后端进行重大修改.但是令牌生命周期短意味着用户因令牌已过期而不断被注销.>旋转代币.也许引入刷新令牌的概念.当用户登录时,为他们提供JWT和刷新令牌.将刷新令牌存储在数据库中.对于经过身份验证的请求,客户端可以使用JWT,但是当令牌过期(或即将过期)时,让客户端使用刷新令牌发出请求以换取新的JWT.这样,您只需在用户登录或要求新的JWT时访问数据库.当用户注销时,您需要使存储的刷新令牌无效.否则,即使用户已经注销,有人在监听连接时仍然可以获得新的JWT.>创建JWT黑名单.根据过期时间,当客户端删除其令牌时,它可能仍然有效一段时间.如果令牌生存期很短,则可能不是问题,但如果您仍希望令牌立即失效,则可以创建令牌黑名单.当后端收到注销请求时,从请求中获取JWT并将其存储在内存数据库中.对于每个经过身份验证的请求,您需要检查内存数据库以查看令牌是否已失效.为了保持较小的搜索空间,您可以从黑名单中删除已经过期的令牌.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读