Java Springboot Security-处理依赖项注入

时间:2020-10-30 19:55:13

标签: java spring-boot spring-security dependency-injection

我正在研究Java Springboot REST API。为了访问端点,用户必须向外部Identity Server服务发送请求,该服务将返回令牌。然后,该令牌将在标头“授权”中发送到此API,该API将在允许请求传递到控制器之前检查用户是否在数据库中。

我对Java有点陌生,所以我在互联网上使用了一些示例来说明如何实现这一点。我到达了请求进入的地方,被过滤,然后我可以允许它通过或不通过。现在,我需要在检查数据库的地方添加部分,以查看用户是否在那里。我对此有一些疑问。

我在gradle中添加了以下软件包:

  • org.springframework.boot:spring-boot-starter-security
  • io.jsonwebtoken:jjwt:0.7.0(不确定是否确实需要这样做,示例全部包括令牌生成,而我在此API中没有这样做)

这是我在安全软件包中实现的代码。这是在尝试添加数据库集成之前,它可以运行并起作用:

WebSecurityConfig.java:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable().authorizeRequests()
        .antMatchers(httpMethod.GET, "/user").authenticated()
        .and()
        .addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    // this following one might not be necessary, it was in the example but I don't think it's being used
    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("admin")
            .password("password")
            .roles("ADMIN");

    }
}

JWTAuthenticationFilter.java:

public class JWTAuthenticationFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {
                
                Authentication authentication = TokenAuthenticationService.getAuthentication((HttpServletRequest) request);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                filterChain.doFilter(request, response);
            }
}

TokenAuthenticationService.java:

public class TokenAuthenticationService {

    static final String SECRET = "mySecret";
    static final String TOKEN_PREFIX = "Bearer";
    static final String HEADER_STRING = "Authorization";

    static Authentication getAuthentication(httpServletRequest request) {
        String token = request.getHeader(HEADER_STRING);
        
        // do a bunch of stuff with the token to get the user Identity

        if (userID != null) {

            // here I need to call a method from a class in gateway, to find this user in the database..
            // if not found I'll return null
            
            return new UsernamePasswordAuthenticationToken(userID, null, Collections.emptyList());
        }

        return null;
    }


}

这就是现在正在运行的代码。但是,我无法从getAuthentication内部调用外部方法,因为它是静态的,因此为了调用网关方法,我将其设置为非静态。 因为我将其设置为非静态,所以必须更改在JWTAuthenticationFilter中的调用方式。不必直接调用该方法,而必须添加以下行:

TokenAuthenticationService tokenAuthenticationService = new TokenAuthenticationService();

,然后使用getAuthentication呼叫tokenAuthenticationService

之后,我尝试直接调用方法userGateway.getByUserID。但我需要UserGateway的瞬间。我无法直接初始化UserGatewayImplementation的实例。 这不仅违反了我们在本项目中遵循的依赖注入原理,而且还需要初始化该类使用的其他东西。还有其他东西还需要另一个对象,依此类推。

因此,我将注释@RequiredArgsConstructor添加到了类中,并赋予了以下内容:

private final UserGateway userGateway;

以便我可以打电话给this.userGateway.getByUserID(userID)

但是,由于我必须创建TokenAuthenticationService的实例(因为该方法不再是静态的),并且我向TokenAuthenticationServiceuserGateway)添加了一个属性,因此我在UserGateway中创建tokenAuthenticationService时将JWTAuthenticationFilter的实例传递给构造函数。

就像以前一样,我不能那样做。因此,我将@RequiredArgsConstructor添加到了JWTAuthenticationFilter类中,并赋予了该属性:

private final TokenAuthenticationService tokenAuthenticationService;

以便我可以用它来调用getAuthentication

这当然导致了WebSecurityConfig中的相同问题。在这一行:

.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

它创建了JWTAuthenticationFilter的实例,但是现在它要我将TokenAuthenticationService的实例传递给它,因为它具有该属性。 所以我做了同样的事情,将@RequiredArgsConstructor添加到WebSecurityConfig类中,并赋予了该属性:

private final JWTAuthenticationFilter jwtAuthenticationFilter;

,然后将此jwtAuthenticationFilter传递给addFilterBefore

完成所有这些操作会使编辑器停止抱怨,但是当我尝试运行该应用程序时,它给了我以下错误:

***************************
APPLICATION FAILED TO START
***************************
 
Description:
 
Parameter 0 of constructor in (path).security.WebSecurityConfig required a bean of type '(path).security.JWTAuthenticationFilter' that could not be found.
 

Action:
 
Consider defining a bean of type '(path).security.JWTAuthenticationFilter' in your configuration. 

我搜索了此错误,并尝试将@Bean添加到JWTAuthenticationFilter,添加到doFilter,依此类推,但这没有用,我并不感到惊讶,因为我正在这样做盲目地。 即使简短,也请多多帮助。最终,我只想能够从getAuthentication中的另一个类调用一个方法,以检查数据库并查看用户是否在那里。 显然,我需要了解有关Java和Springboot的更多信息,但不幸的是,我很着急进行这项工作。

1 个答案:

答案 0 :(得分:1)

盲目尝试了许多东西之后,我最终自己找到了答案。我只需要将注释@Component添加到类JWTAuthenticationFilterTokenAuthenticationService中。现在还不能完全解释它,但是如果有人需要它,我会留在这里。

相关问题