java - Spring security - 错误导致性能问题
问题描述
我遇到了 SpringBoot 应用程序的问题。我的 ICS 报告了这个 API的高响应时间,但我的代码指标表明一切都很好,例如,发送到我的 API 的查询只需要 50 毫秒来运行“业务”代码,但有效响应需要超过 500 毫秒!
我的 JVM 的内部日志说,在每个请求上,我都有一个“ UsernameNotFoundExcption ”,即使凭据是正确的并且 API 工作正常。这就是为什么我认为我的问题来自 SpringSecurity 层但我无法确定原因。
我的切入点:
@Component
public class BasicAuthenticationPoint extends BasicAuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
throws IOException, ServletException {
response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
writer.println("HTTP Status 401 - " + authEx.getMessage());
}
@Override
public void afterPropertiesSet() throws Exception {
setRealmName("MYAPI");
super.afterPropertiesSet();
}
}
还有我的适配器:
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private BasicAuthenticationPoint basicAuthenticationPoint;
@Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
HttpSecurity httpSec = http.csrf().disable();
httpSec = httpSec.authorizeRequests()
.antMatchers("/my-business-resources/**").hasRole("USER")
.antMatchers("/actuator/**").hasRole("ADMIN")
.and();
httpSec.httpBasic().authenticationEntryPoint(basicAuthenticationPoint).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// Load users file
Resource confFile = resourceLoader.getResource("classpath:users.list");
// Returns users from the configuration file <username, password (BCrypted), admin (boolean)>
List<ApiUser> users = ApiUtils.getUsersFromFile(confFile);
for(ApiUser u : users){
// Add the username/password to the in-memory authentication manager
if (u.admin)
auth.inMemoryAuthentication().withUser(u.username).password(u.password).roles("USER", "ADMIN");
else
auth.inMemoryAuthentication().withUser(u.username).password(u.password).roles("USER");
}
}
}
我错过了什么 ?
PS:我的 Spring Boot 应用程序被打包为 WAR 并在 Tomcat 服务器内执行以实现标准化目的。
编辑:
这是完整的 UsernameNotFound 堆栈跟踪(ICS 格式):
Exception Details
Type: UsernameNotFoundException
Exception Class: org.springframework.security.core.userdetails.UsernameNotFoundException
API: Exception
Thread Name: https-openssl-apr-9343-exec-10 <522634598>
Exception StackTrace
Method Class Line File Name
loadUserByUsername org.springframework.security.provisioning.InMemoryUserDetailsManager 146 <unknown>
retrieveUser org.springframework.security.authentication.dao.DaoAuthenticationProvider 104 <unknown>
authenticate org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider 144 <unknown>
authenticate org.springframework.security.authentication.ProviderManager 174 <unknown>
authenticate org.springframework.security.authentication.ProviderManager 199 <unknown>
doFilterInternal org.springframework.security.web.authentication.www.BasicAuthenticationFilter 180 <unknown>
doFilter org.springframework.web.filter.OncePerRequestFilter 107 <unknown>
doFilter org.springframework.security.web.FilterChainProxy$VirtualFilterChain 334 <unknown>
doFilter org.springframework.security.web.authentication.logout.LogoutFilter 116 <unknown>
doFilter org.springframework.security.web.FilterChainProxy$VirtualFilterChain 334 <unknown>
doFilterInternal org.springframework.security.web.header.HeaderWriterFilter 66 <unknown>
doFilter org.springframework.web.filter.OncePerRequestFilter 107 <unknown>
doFilter org.springframework.security.web.FilterChainProxy$VirtualFilterChain 334 <unknown>
doFilter org.springframework.security.web.context.SecurityContextPersistenceFilter 105 <unknown>
doFilter org.springframework.security.web.FilterChainProxy$VirtualFilterChain 334 <unknown>
doFilterInternal org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter 56 <unknown>
doFilter org.springframework.web.filter.OncePerRequestFilter 107 <unknown>
doFilter org.springframework.security.web.FilterChainProxy$VirtualFilterChain 334 <unknown>
doFilterInternal org.springframework.security.web.FilterChainProxy 215 <unknown>
doFilter org.springframework.security.web.FilterChainProxy 178 <unknown>
invokeDelegate org.springframework.web.filter.DelegatingFilterProxy 357 <unknown>
doFilter org.springframework.web.filter.DelegatingFilterProxy 270 <unknown>
internalDoFilter org.apache.catalina.core.ApplicationFilterChain 193 <unknown>
doFilter org.apache.catalina.core.ApplicationFilterChain 166 <unknown>
doFilter org.springframework.boot.web.servlet.support.ErrorPageFilter 130 <unknown>
access$000 org.springframework.boot.web.servlet.support.ErrorPageFilter 66 <unknown>
doFilterInternal org.springframework.boot.web.servlet.support.ErrorPageFilter$1 105 <unknown>
doFilter org.springframework.web.filter.OncePerRequestFilter 107 <unknown>
doFilter org.springframework.boot.web.servlet.support.ErrorPageFilter 123 <unknown>
internalDoFilter org.apache.catalina.core.ApplicationFilterChain 193 <unknown>
doFilter org.apache.catalina.core.ApplicationFilterChain 166 <unknown>
filterAndRecordMetrics org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter 155 <unknown>
filterAndRecordMetrics org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter 123 <unknown>
doFilterInternal org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter 108 <unknown>
doFilter org.springframework.web.filter.OncePerRequestFilter 107 <unknown>
internalDoFilter org.apache.catalina.core.ApplicationFilterChain 193 <unknown>
doFilter org.apache.catalina.core.ApplicationFilterChain 166 <unknown>
doFilterInternal org.springframework.web.filter.CharacterEncodingFilter 200 <unknown>
doFilter org.springframework.web.filter.OncePerRequestFilter 107 <unknown>
internalDoFilter org.apache.catalina.core.ApplicationFilterChain 193 <unknown>
解决方案
好的,经过大量调试,我发现了问题!
问题出在我用来填充内存身份验证器的代码中:
for(ApiUser u : users){
// Add the username/password to the in-memory authentication manager
if (u.admin)
auth.inMemoryAuthentication().withUser(u.username).password(u.password).roles("USER", "ADMIN");
else
auth.inMemoryAuthentication().withUser(u.username).password(u.password).roles("USER");
}
auth.inMemoryAuthentication()
多次调用的事实InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>
每次都会创建一个新的(Spring 代码),因此我们有与用户一样多的不同AuthenticationManager
用户(每个用户一个用户),因此对每个请求执行多次身份验证过程。
这是我修复错误的方法:
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// Load users file
Resource confFile = resourceLoader.getResource("classpath:users.list");
// Returns users from the configuration file <username, password (BCrypted), admin (boolean)>
List<ApiUser> users = ApiUtils.getUsersFromFile(confFile);
@SuppressWarnings("rawtypes")
UserDetailsBuilder udb = null;
for(ApiUser u : users){
// Add the username/password to the in-memory authentication manager
if (udb == null)
udb = auth.inMemoryAuthentication().withUser(u.username).password(u.password);
else
udb = udb.and().withUser(u.username).password(u.password);
if (u.admin)
udb.roles("USER", "ADMIN");
else
udb.roles("USER");
}
}
现在我的平均响应时间是 80 毫秒
推荐阅读
- python - 从 URL 下载文件并在 python 中压缩下载的文件
- powershell - 需要使用 PnP PowerShell 在 SharePoint Online 中添加语言翻译器
- python-3.x - 使用 Python 创建具有特定网格的 2D 坐标
- json - TypeScript React 项目中 JSON 数据的列子集
- css - MailChimp MergeTags CSS/HTML - 根据字符串中的字符更改颜色
- c - 使用地图将数据从用户空间发送到 bpf 程序的问题
- python - 如果特定行的最大日期时间在最小值 - 数据帧中其余行的最大日期时间范围内,则创建一个计数器
- java - 最小跳转数组递归时间复杂度应为 O(n^n) 或 O(n!)
- postgresql - 为什么会出现“DELETE 处或附近的语法错误”错误?
- botframework - 自适应卡片 Action.ShowCard 按钮聚焦问题