Java Springboot安全性-处理依赖项注入
我正在开发一个JavaSpringBootRESTAPI。为了访问端点,用户必须向外部Identity Server服务发送请求,该服务将返回令牌。然后,该令牌将在头授权中发送到此API,该API将在允许请求通过控制器之前检查用户是否在数据库中 我对Java有点陌生,所以我在互联网上用了一些例子来说明如何做到这一点。我到达了一个点,请求进入,被过滤,然后我可以允许它通过或不通过。现在我需要添加检查数据库的部分,以查看用户是否在那里。我对此有些问题 我向gradle添加了以下软件包:Java Springboot安全性-处理依赖项注入,java,spring-boot,spring-security,dependency-injection,Java,Spring Boot,Spring Security,Dependency Injection,我正在开发一个JavaSpringBootRESTAPI。为了访问端点,用户必须向外部Identity Server服务发送请求,该服务将返回令牌。然后,该令牌将在头授权中发送到此API,该API将在允许请求通过控制器之前检查用户是否在数据库中 我对Java有点陌生,所以我在互联网上用了一些例子来说明如何做到这一点。我到达了一个点,请求进入,被过滤,然后我可以允许它通过或不通过。现在我需要添加检查数据库的部分,以查看用户是否在那里。我对此有些问题 我向gradle添加了以下软件包: boot:
- boot:springbootstartersecurity
- io.jsonwebtoken:jjwt:0.7.0(不确定这是否真的有必要,示例中都包含令牌生成,我在这个API中没有这样做)
@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();
然后使用tokenAuthenticationService
调用getAuthentication
之后,我尝试直接调用方法userGateway.getByUserID
。但是我需要一个瞬间的UserGateway
。我无法直接初始化UserGatewayImplementation
的实例。
这不仅违背了我们在这个项目中遵循的依赖注入原则,还需要初始化该类使用的其他东西。其他东西也需要另一个对象等等
因此,我在类中添加了注释@RequiredArgsConstructor
,并给出了以下内容:
private final UserGateway userGateway;
这样我就可以调用this.userGateway.getByUserID(userID)
但是,由于我必须创建TokenAuthenticationService
的实例(因为该方法不再是静态的),并且我向TokenAuthenticationService
(userGateway
)添加了一个属性,它希望我在JWTAuthenticationFilter
中创建tokenAuthenticationService
时,将UserGateway
的实例传递给构造函数
就像以前一样,我不能那样做。因此,我将@RequiredArgsConstructor
添加到类JWTAuthenticationFilter
,并赋予它以下属性:
private final TokenAuthenticationService tokenAuthenticationService;
private final JWTAuthenticationFilter jwtAuthenticationFilter;
这样我就可以用它调用getAuthentication
这当然会导致WebSecurityConfig
中出现同样的问题。在这方面:
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
它创建了一个JWTAuthenticationFilter
的实例,但现在它希望我将TokenAuthenticationService
的实例传递给它,因为它具有该属性。
因此,我做了同样的事情,将@RequiredArgsConstructor
添加到WebSecurityConfig
类中,并赋予它以下属性:
private final TokenAuthenticationService tokenAuthenticationService;
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的知识,但不幸的是,我急于让它发挥作用。在盲目尝试了很多东西之后,我最终自己找到了答案。我只需要在类
JWTAuthenticationFilter
和TokenAuthenticationService
中添加注释@Component
。现在还不能完全解释,但我会把它留在这里,以防其他人需要。Lombok与这一切无关。它不“创建对象”,它只是静态地(在编译时)生成一些样板代码,比如构造函数。所有这些都是非常透明的,你可以手工完成。我想如果你不提龙目山,你的问题会有好处的。@MichaelPiefel我明白了。那么,我将删除对Lombok的引用。谢谢。很抱歉,昨天晚上我帮不了你什么忙,但我很高兴你现在已经解决了这个问题。某个地方的某个人需要实例化你的WebSecurityConfig
类,也就是说,调用它的构造函数。在这个场景中,这就是Spring框架本身。但是当WebSecurityConfig
构造函数需要一个参数(任何参数)时,Spring需要知道从哪里获得该参数。有不同的方式告诉Spring考虑什么,但是添加<代码> @组件< /代码>是其中之一(即使是最好的,通常);Spring将扫描候选bean的类路径,并考虑所有带有此注释的类(或<代码> @ Service < /Cord>和其他一些)。谢谢,这很有帮助!