在身份验证过滤器中添加自定义声明。在过滤器中获取用户 ID。弹簧靴

Posted

技术标签:

【中文标题】在身份验证过滤器中添加自定义声明。在过滤器中获取用户 ID。弹簧靴【英文标题】:Add custom claim in authentication filter. Get user id in filter. Spring boot 【发布时间】:2019-09-25 11:29:42 【问题描述】:

我想将用户 ID 作为自定义声明添加到我的令牌中。

但我无法在过滤器中获取用户 ID,因为依赖注入在过滤器中不起作用。我尝试使用我的 UserService 的构造函数,但在这个服务中我有存储库,我 @Autowiring 所以在调试模式下我看到 userRepository 字段为空。

我的问题是如何添加此自定义声明? 也许是另一种添加方式。

我正在关注本教程(没有“旁白”一章) https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/#User-Authentication-and-Authorization-on-Spring-Boot

这是我尝试添加此声明的过滤器

package com.kamczi.auth;

import com.auth0.jwt.JWT;
import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
import com.fasterxml.jackson.databind.ObjectMapper;
import static com.kamczi.auth.SecurityConstants.EXPIRATION_TIME;
import static com.kamczi.auth.SecurityConstants.HEADER_STRING;
import static com.kamczi.auth.SecurityConstants.SECRET;
import static com.kamczi.auth.SecurityConstants.TOKEN_PREFIX;
import com.kamczi.entities.User;
import com.kamczi.repository.UserRepository;
import com.kamczi.services.UserService;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 *
 * @author Kamil
 */
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter   
    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) 
        this.authenticationManager = authenticationManager;
    

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException 
        try
            User user = new ObjectMapper()
                    .readValue(request.getInputStream(), User.class);

            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            user.getUsername(),
                            user.getPassword(),
                            new ArrayList<>())
                    );
         catch(IOException e)
            throw new RuntimeException(e);
        
    

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException 
        String username = ((org.springframework.security.core.userdetails.User) authResult.getPrincipal()).getUsername();
        String token = JWT.create()
                //.withClaim("id", userService.findByUsername(username).getUser_id()) need implementation
                .withSubject(username)
                .withExpiresAt(new Date(System.currentTimeMillis()+EXPIRATION_TIME))
                .sign(HMAC512(SECRET.getBytes()));
        response.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
    



【问题讨论】:

【参考方案1】:

尝试使用@Component 标记您的过滤器。 @Autowired 仅适用于 Spring 管理的 bean(组件)。

或者您可以使用构造函数手动添加过滤器并将存储库传递给它。

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter 

    @Autowired
    UsersRepository usersRepo;

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.addFilterAt(new JWTAuthenticationFilter(usersRepo), UsernamePasswordAuthenticationFilter.class);
    


【讨论】:

您的第二个建议效果很好。但我做了这样的事情:.addFilter(new JWTAuthenticationFilter(authenticationManager(), userRepository))。我真的不知道您为什么使用“UsernamePasswordAuthenticationFilter.class”作为参数。它有什么目的吗? 它替换过滤器链中指定类型的现有bean。 有影响吗,你能解释一下它是否重要吗? 仅当您想更改默认过滤器弹簧时才重要,例如。或者你已经有一些授权过滤器,你想用你的实现来替换它。

以上是关于在身份验证过滤器中添加自定义声明。在过滤器中获取用户 ID。弹簧靴的主要内容,如果未能解决你的问题,请参考以下文章

AD B2C - 重新获取令牌后缺少自定义声明

在 jwt-auth laravel 中获取自定义声明

OpenID Connect:如何在客户端凭证流中添加自定义声明数据

从 Flutter 为 Firebase 身份验证设置自定义声明

ASP.NET Core 2.1 Jwt 设置自定义声明

AD B2C 自定义策略自定义声明出现错误“无法验证提供的信息”。注册时