JWT身份验证,而无需获取每个请求的用户详细信息 [英] JWT authentication without fetching user details on each request
问题描述
我正在Spring Security中实现JWT身份验证. 我有预定义的角色,例如.普通用户,管理员等.
I'm implementing JWT authentication in Spring Security. I have predefined roles, eg. regular user, admin etc.
我有以下令牌有效载荷:
I have following payload of token:
{
"sub": "nick",
"iat": "<some_date>",
"exp": "<some_date+1h>",
"scopes": [
"ROLE_USER",
"ROLE_ADMIN"
]
}
到目前为止,我看到的大多数实现都基于id/username/email从数据库中检索用户详细信息,然后使用此数据来创建身份验证(例如,通过对UsernamePasswordAuthenticationToken进行身份验证). 对我来说,这实际上是一种更可取的方法,因为我总是拥有最新的特权和限制(例如,是否禁止用户使用),并且与收益相比,时间开销并不算太大.
Most of the implementations I saw so far retrieve user details from database based on id/username/email and then use this data to create authentication (eg. by authenticating UsernamePasswordAuthenticationToken). For me it's actually a preferrable way to go, because I always have up to date privileges and restrictions (eg. whether user was banned) and time overhead is not so big compared to benefits.
我很好奇我如何仅基于传入请求中包含的角色(在其授权标头令牌中)使用Spring Security来实现授权.我希望能够在正确路由请求后访问控制器中的用户标识符.仅根据检查到期时间和角色有效性进行的令牌验证就足够了吗?
I'm just curious how could I implement authorization with Spring Security based only on roles included in incoming request (in its authorization header token). I want just to be able to access user identifier in controller after the request is routed appropriately. Would token validation based only on checking expiration time and roles validity be sufficient?
推荐答案
由于有关用户角色的信息是令牌的一部分(在scopes
声明中),因此可以仅基于令牌创建身份验证对象,而无需进一步访问数据库.
Since the information about the user's roles are part of your token (in the scopes
claim), it's possible to create the authentication object based on the token alone, without further access to the database.
在下面的示例中,createAuthentication()
方法将令牌转换为Spring Security Authentication
对象.
In the following example, the createAuthentication()
method transforms the token into a Spring Security Authentication
object.
public class JWTFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String jwt = // resolveToken(httpServletRequest);
this.createAuthentication(jwt).ifPresent(authentication -> {
SecurityContextHolder.getContext().setAuthentication(authentication);
});
filterChain.doFilter(servletRequest, servletResponse);
}
public Optional<Authentication> createAuthentication(String token) {
Jws<Claims> jwsClaims = validateToken(token);
if (jwsClaims == null) {
return Optional.empty();
}
Claims claims = jwsClaims.getBody();
String scopesString = claims.get("scopes").toString();
String[] authStrings = scopesString.split(",");
Collection<? extends GrantedAuthority> authorities =
Arrays.stream(authStrings)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
String subject = claims.getSubject();
org.springframework.security.core.userdetails.User principal = new User(subject, "", authorities);
return Optional.of(new UsernamePasswordAuthenticationToken(principal, token, authorities));
}
private Jws<Claims> validateToken(String authToken) {
try {
Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken);
return claims;
} catch ...
}
}
这篇关于JWT身份验证,而无需获取每个请求的用户详细信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!