Keycloak secured Spring Boot Application: Try to configure publicly available pages
我们有一个Keycloak服务器,用于保护我们的Spring Boot应用程序。到目前为止,一切正常。但是,我们现在需要一个忘记密码页面,该页面必须无需登录即可访问。我们无法做到这一点。
我们正在实现
1 2 3 4 5 6 | super.configure(http); http.csrf().disable() .exceptionHandling() .accessDeniedPage("/accessDenied"); http.anonymous.disable(); http.authorizeRequests(); |
仅使用该代码,实际上除根页面外,每个页面都可以自由访问。一旦我们添加对
1 2 | http.authorizeRequests().antMatchers(HttpMethod.GET,"/public/forgotPassword").permitAll() .anyRequest().fullyAuthenticated(); |
如上所述,结果是每个页面都需要身份验证,也需要public / forgotPassword页面。
有谁知道可能是什么问题?
提前谢谢!
我已经实现了springboot.keycloak.mre1,以简化的方式演示了我以前从事的项目如何类似地实现了我认为您所要求的内容。
简而言之,解决方案的要点是...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | … public class SecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { super.configure(http); http.authorizeRequests().antMatchers("/login","/login.html") .permitAll().antMatchers("/dashboard","/dashboard.html") .authenticated(); } … } |
构建和运行MRE的步骤很简单。但是,如果您在构建或运行它时遇到困难,请告诉我是否可以提供任何帮助。
如果我完全误解了您的要求,请随时克隆和修改项目,使其更像您的用例。如果您随后上传修改,并在存储库的"问题"区域中详细说明用例的细节,我将进行调查并与您联系。
1MRE使用docker-compose,因为其原始项目基于其基础。
在我的应用程序中,我正在使用以下配置方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.wissance.orgstructure.application.configuration; import com.goodt.drive.goals.application.authentication.AppAuthenticationEntryPoint; import com.goodt.drive.goals.application.services.users.KeyCloakUserInfoExtractorService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.headers().frameOptions().sameOrigin(); // it is to fix issue with h2-console access http.cors(); http.csrf().disable() .authorizeRequests().antMatchers("/","/callback","/login**","/webjars/**","/error**").permitAll() .and() .authorizeRequests().antMatchers("/api/**").authenticated() .and() .authorizeRequests().antMatchers("/h2-console/**").permitAll() .and() .authorizeRequests().antMatchers("/swagger-ui.html").permitAll() .and() .authorizeRequests().antMatchers("/swagger-ui/**").permitAll() .and() .exceptionHandling().authenticationEntryPoint(new AppAuthenticationEntryPoint()) .and() .logout().permitAll().logoutSuccessUrl("/"); } @Bean public PrincipalExtractor getPrincipalExtractor(){ return new KeyCloakUserInfoExtractorService(); } @Autowired private ResourceServerTokenServices resourceServerTokenServices; } @ControllerAdvice public class AppAuthenticationEntryPoint implements AuthenticationEntryPoint{ @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { // 401 logger.debug(String.format("Access to resource is denied (401) for request: "%s" message: "%s"", request.getRequestURL(), authException.getMessage())); setResponseError(response, HttpServletResponse.SC_UNAUTHORIZED,"Authentication Failed"); } @ExceptionHandler (value = {AccessDeniedException.class}) public void commence(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { // 403 logger.debug(String.format("Access to resource is forbidden (403) for request: "%s" message: "%s"", request.getRequestURL(), accessDeniedException.getMessage())); setResponseError(response, HttpServletResponse.SC_FORBIDDEN, String.format("Access Denies: %s", accessDeniedException.getMessage())); } @ExceptionHandler (value = {NotFoundException.class}) public void commence(HttpServletRequest request, HttpServletResponse response, NotFoundException notFoundException) throws IOException { // 404 logger.debug(String.format("Object was not found (404) for request: "%s" message: "%s"", request.getRequestURL(), notFoundException.getMessage())); setResponseError(response, HttpServletResponse.SC_NOT_FOUND, String.format("Not found: %s", notFoundException.getMessage())); } @ExceptionHandler (value = {Exception.class}) public void commence(HttpServletRequest request, HttpServletResponse response, Exception exception) throws IOException { logger.error(String.format("An error occurred during request: %s %s error message: %s", request.getMethod(), request.getRequestURL(), exception.getMessage())); // 500 setResponseError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, String.format("Internal Server Error: %s", exception.getMessage())); } private void setResponseError(HttpServletResponse response, int errorCode, String errorMessage) throws IOException{ response.setStatus(errorCode); response.getWriter().write(errorMessage); response.getWriter().flush(); response.getWriter().close(); } private final Logger logger = LoggerFactory.getLogger(this.getClass()); } |
下面列出了与KeyCloak相关的spring security(application-local.yml)的
Config,在我的应用中,我至少有3个不同的keycloak服务器,并且不时切换它们,我所有的KeyCloak值都从基本设置传递( application.yml)当前在appConfig.keyCloak.using中定义为选定密钥斗篷的yml占位符? Spring Security配置部分的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | security: basic: enabled: false oauth2: client: clientId: ${appConfig.keyCloak.using.clientId} clientSecret: ${appConfig.keyCloak.using.clientSecret} accessTokenUri: ${appConfig.keyCloak.using.baseUrl}/protocol/openid-connect/token userAuthorizationUri: ${appConfig.keyCloak.using.baseUrl}/protocol/openid-connect/auth authorizedGrantTypes: code token scope: local username: ${appConfig.keyCloak.using.serviceUsername} password: ${appConfig.keyCloak.using.servicePassword} resource: userInfoUri: ${appConfig.keyCloak.using.baseUrl}/protocol/openid-connect/userinfo |
KeyCloak服务器配置之一的示例:
1 2 3 4 5 | baseUrl: http://99.220.112.131:8080/auth/realms/master clientId: api-service-agent clientSecret: f4901a37-efda-4110-9ba5-e3ff3b221abc serviceUsername: api-service-agent servicePassword: x34yui9034*&1 |
在上面的示例中,URL中具有