MLu*_*ugo 6 java spring spring-security spring-boot spring-security-oauth2
编辑:
从 org.springframework.security 登录:
2022-01-17 12:31:03.495 IST
2022-01-17 10:31:03.495 DEBUG [080-exec-5] o.s.s.w.s.SessionManagementFilter - Request requested invalid session id D5F8BA31A3D7466AK3K3C8EA26A4F037
Default
2022-01-17 12:31:03.495 IST
2022-01-17 10:31:03.495 DEBUG [080-exec-5] o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
Debug
2022-01-17 12:31:03.495 IST
"Request requested invalid session id D5F8BA31A3D7466AK3K3C8EA26A4F037"
Debug
2022-01-17 12:31:03.495 IST
"Set SecurityContextHolder to anonymous SecurityContext"
Default
2022-01-17 12:31:03.494 IST
2022-01-17 10:31:03.494 DEBUG [080-exec-5] o.s.s.w.c.SecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext
Debug
2022-01-17 12:31:03.494 IST
"Set SecurityContextHolder to empty SecurityContext"
Default
2022-01-17 12:31:03.493 IST
2022-01-17 10:31:03.493 DEBUG [080-exec-5] o.s.security.web.FilterChainProxy - Securing GET /logo192.png
Debug
2022-01-17 12:31:03.493 IST
"Securing GET /logo192.png"
Run Code Online (Sandbox Code Playgroud)
***但是,如果我在获得有效身份验证后查看日志中的一些请求:
调试 2022-01-17 12:31:03.945 IST“将 SecurityContextHolder 设置为 SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=com..security.oauth.CustomOAuth2User @、Credentials=[PROTECTED]、Authenticated=true、Details=WebAuthenticationDetails [RemoteIpAddress= ***,SessionId=9438C880A19C93AADJI206B9B8B3386],授予权限=[ROLE_USER,SCOPE_https://www.googleapis.com/auth/userinfo.email,SCOPE_https://www.googleapis.com/auth/userinfo.profile,SCOPE_openid]] ]“ 调试
2022-01-17 12:31:03.945 IST“检索到 SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=com..security.oauth.CustomOAuth2User @,凭据=[受保护],Authenticated=true,详细信息=WebAuthenticationDetails [RemoteIpAddress=*** ,SessionId=9438C880A19C93AADJI206B9B8B3386],授予权限=[ROLE_USER,SCOPE_https://www.googleapis.com/auth/userinfo.email,SCOPE_https://www.googleapis.com/auth/userinfo.profile,SCOPE_openid]]]“调试
2022-01-17 12:31:03.945 IST“检索到的 SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=com..security.oauth.CustomOAuth2User @,凭据=[受保护],Authenticated=true,详细信息=WebAuthenticationDetails [RemoteIpAddress=*** ,SessionId=9438C880A19C93AADJI206B9B8B3386],授予权限=[ROLE_USER,SCOPE_https://www.googleapis.com/auth/userinfo.email,SCOPE_https://www.googleapis.com/auth/userinfo.profile,SCOPE_openid]]]“默认
2022-01-17 12:31:03.944 IST 2022-01-17 10:31:03.944 调试 [080-exec-8] ossecurity.web.FilterChainProxy - 保护 GET /auth/api/getBasicInfo
看起来session id不一致
我使用 spring security 内置的 oauth2 社交登录选项,我使用 onAuthenticationSuccess 方法实现了 OAuth2LoginSuccess 类,并在其中获取与我从 oauth 获得的社交 id 相对应的用户:
CustomOAuth2User oAuth2User = (CustomOAuth2User) authentication.getPrincipal();
int sociald = oAuth2User.getAttribute("id");
User user = usersUtils.getUserBySocailId(socialId);
enter code here
// add the user details to the Auth
SecurityContextHolder.clearContext();
((OAuth2AuthenticationToken) authentication).setDetails(user);
SecurityContextHolder.getContext().setAuthentication(authentication);
Run Code Online (Sandbox Code Playgroud)
如果我在 onAuthenticationSuccess 内部进行调试,我可以看到包含所有用户详细信息的有效身份验证。
登录后,我重定向到主页并向服务器发送一个 auth get 请求以检查是否有用户登录。
问题是 50% 的情况下请求会成功完成,并且用户可以发出经过身份验证的请求。
但另外 50% 我会自动重定向到登录页面,当我检查日志时,会看到 Spring boot 说用户未经身份验证并且身份验证丢失。
但在 onAuthenticationSuccess 中我总能看到正确的身份验证。
我的 ApplicationSecurityConfig 如下所示:
http.csrf().disable().authorizeRequests()
.antMatchers("/login*", "/signin/**", "/signup/**", "/oauth2/**").permitAll()
.antMatchers(Constants.ADMIN_PREFIX + "/**").hasRole("ADMIN")
.antMatchers(Constants.AUTH_PREFIX + "/**").hasAnyRole("ADMIN", "USER")
.antMatchers(Constants.PUBLIC_PREFIX + "/**").permitAll()
.anyRequest().permitAll()
.and()
.exceptionHandling().authenticationEntryPoint(new UnauthenticatedRequestHandler())
.and()
.formLogin()
.passwordParameter("password")
.usernameParameter("email")
.loginPage("/Login")
.loginProcessingUrl("/loginSecure").permitAll().successHandler(new LoginSuccess()).failureHandler(new FailureSuccess())
.and()
.oauth2Login()
.loginPage("/Login")
.userInfoEndpoint()
.userService(oAuth2UserService)
.and()
.successHandler(new OAuth2LoginSuccess())
.and()
.rememberMe()
.rememberMeParameter("remember-me")
.tokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(21))
.userDetailsService(this.applicationUserService)
.and()
.logout()
.clearAuthentication(true).invalidateHttpSession(true).logoutSuccessUrl("/login")
.addLogoutHandler(new CustomLogOutHandler());
Run Code Online (Sandbox Code Playgroud)
这是我检查用户是否登录的功能:
@GetMapping(Constants.AUTH_PREFIX + "/checkUserLogged")
public Integer checkUserLogged(Authentication authentication,HttpServletRequest request) {
try{
if (authentication != null) {
User (User) authentication.getDetails();
if (user == null) {
return -1;
}
return user.getId();
}
}
catch (Exception e){
logger.warning(e.getLocalizedMessage());
}
return -1;
}
Run Code Online (Sandbox Code Playgroud)
但是当问题发生时,它无法运行控制器,因为 spring security 之前返回了未经授权的错误。
预先感谢您的帮助
我找到了解决方案,希望这能有所帮助。
对我来说造成问题的是 GCP 和 GAE 使用服务器的多个实例,如果用户登录某个实例并不意味着其他实例也熟悉它,因为 Spring HTTPSession 是在内存中的。
我使用 application.properties 中的以下配置将会话平台切换为使用 spring-session jdbc :
spring.session.store-type=jdbc
Run Code Online (Sandbox Code Playgroud)
-- 您可以使用redis代替jdbc,只要会话存储在所有实例之间的共享位置即可。
还将事务管理器添加到 SecurtityConfig 中:
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
Run Code Online (Sandbox Code Playgroud)
并添加了以下配置:
http.csrf().disable()
.sessionManagement()
.maximumSessions(1)
.and()
.sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
Run Code Online (Sandbox Code Playgroud)
此外,像 @stringy05 提到的 authrizenClient 存储库也需要更新:
/**
* Use the servlet container session store for authorized OAuth2 Clients
*/
@Bean
public OAuth2AuthorizedClientRepository authorizedClientRepository() {
return new HttpSessionOAuth2AuthorizedClientRepository();
}
Run Code Online (Sandbox Code Playgroud)
并将 .authorizedClientRepository 行添加到 httpconfig:
....
.oauth2Login()
.loginPage("/Login")
.authorizedClientRepository(authorizedClientRepository)
.authorizationEndpoint().and()
.userInfoEndpoint()
.userService(oAuth2UserService)
.and()
.successHandler(new OAuth2LoginSuccess())
Run Code Online (Sandbox Code Playgroud)
....
关于 GAE,我将以下行添加到 app.yaml 文件中:
network:
session_affinity: true
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1778 次 |
| 最近记录: |