我正在研究Java Springboot REST API。为了访问端点,用户必须向外部Identity Server服务发送请求,该服务将返回令牌。然后,该令牌将在标头“授权”中发送到此API,该API将在允许请求传递到控制器之前检查用户是否在数据库中。
我对Java有点陌生,所以我在互联网上使用了一些示例来说明如何实现这一点。我到达了请求进入的地方,被过滤,然后我可以允许它通过或不通过。现在,我需要在检查数据库的地方添加部分,以查看用户是否在那里。我对此有一些疑问。
我在gradle中添加了以下软件包:
这是我在安全软件包中实现的代码。这是在尝试添加数据库集成之前,它可以运行并起作用:
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
的实例(因为该方法不再是静态的),并且我向TokenAuthenticationService
(userGateway
)添加了一个属性,因此我在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的更多信息,但不幸的是,我很着急进行这项工作。
答案 0 :(得分:1)
盲目尝试了许多东西之后,我最终自己找到了答案。我只需要将注释@Component
添加到类JWTAuthenticationFilter
和TokenAuthenticationService
中。现在还不能完全解释它,但是如果有人需要它,我会留在这里。