我有一个Spring Boot 2.2应用程序,可使用组织的CAS实例对用户进行身份验证。当用户请求需要授权(例如,角色)时,spring sec cas集成(过滤器)通过将其转发以登录到CAS服务器来开始进行身份验证,然后将其重定向到其原始请求。好。
现在,我们需要组织外部的用户才能登录(没有CAS帐户)。
我当前的配置有两个问题:
1)它会将所有未经身份验证的用户转发到CAS服务。相反,我想将它们转发到/ login的应用内登录表单(使用POST方法login);这提供了使用CAS登录的选项。 See redacted screenshot of sign in form
2)当用户使用/ login表单并单击使用CAS登录时,我希望他们通过CAS进行身份验证,然后让他们继续其原始请求。
AuthenticationProvider
都处于碎片状态。 dao身份验证提供程序只有在访问/login
时才能访问。否则会发生上述问题1。我不知道如何在单击按钮时配置#2(/login/cas
上的GET?但是当GET被视为新请求却又被放弃时,如何将它们返回到原始请求?)。 >
一种总结预期行为的方案:未经身份验证的用户向受保护区域发出Web请求。用户被转发到/ login
a)他们使用电子邮件和密码(已通过daoAutheticationProvider验证)登录。或
b)他们单击使用CAS按钮登录(已通过casAuthenticationProvider认证)。
通过身份验证后,它们将转发回其原始请求。
这里是代码,全部在java配置中,我们在方法上使用@PreAuthorize,而不在HttpSecurity配置上使用antmatchers,但如果解决方案需要如何工作,愿意返回到antmatchers
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) { auth.authenticationProvider(daoAuthenticationProvider()); auth.authenticationProvider(casAuthenticationProvider()); } private DaoAuthenticationProvider daoAuthenticationProvider() { DaoAuthenticationProvider ap = new DaoAuthenticationProvider(); ap.setUserDetailsService(daoUserDetailsService); //implements UserDetailsService return ap; } private CasAuthenticationProvider casAuthenticationProvider() { CasAuthenticationProvider ap = new CasAuthenticationProvider(); ap.setAuthenticationUserDetailsService(casCustomUserDetailsService); //extends AbstractCasAssertionUserDetailsService ap.setServiceProperties(serviceProperties()); ap.setTicketValidator(new Cas30ServiceTicketValidator(casServiceUrl)); ap.setKey("obviouslyredacted"); return ap; } private CasAuthenticationFilter casAuthenticationFilter() throws Exception { CasAuthenticationFilter filter = new CasAuthenticationFilter(); filter.setFilterProcessesUrl("/j_spring_cas_security_check"); filter.setAuthenticationManager(authenticationManager()); return filter; } private LogoutFilter requestSingleLogoutFilter() { LogoutFilter filter = new LogoutFilter(casServiceUrl + "/logout", new SecurityContextLogoutHandler()); filter.setFilterProcessesUrl("/j_spring_cas_security_logout"); return filter; } private SingleSignOutFilter singleSignOutFilter() { SingleSignOutFilter filter = new SingleSignOutFilter(); filter.setCasServerUrlPrefix(casServiceUrl); filter.setIgnoreInitConfiguration(true); return filter; } private CasAuthenticationEntryPoint casAuthenticationEntryPoint() { CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint(); ep.setLoginUrl(casServiceUrl + "/login"); ep.setServiceProperties(serviceProperties()); return ep; } @Override protected void configure(HttpSecurity http) throws Exception { XFrameOptionsHeaderWriter xframeoptions = new XFrameOptionsHeaderWriter(SAMEORIGIN); XXssProtectionHeaderWriter xxssprotection = new XXssProtectionHeaderWriter(); xxssprotection.setEnabled(true); http .sessionManagement() .sessionCreationPolicy(ALWAYS) .and().csrf().disable() .authorizeRequests() .antMatchers("/login").permitAll() .antMatchers("/css/**").permitAll() .antMatchers("/favicon_192x192.png").permitAll() .anyRequest().authenticated() .and().formLogin() .loginPage("/login") .permitAll() .and().logout() .logoutRequestMatcher(new AntPathRequestMatcher("/dologout")) .invalidateHttpSession(true) .deleteCookies("JSESSIONID") .permitAll() .and().exceptionHandling() .accessDeniedPage(NAV_URL_ERROR + "/403") .and().headers().addHeaderWriter(xframeoptions) .and().headers().addHeaderWriter(xxssprotection); //Only enable CAS in Production or SPI if (activeProfile.equals(ENV_PRODUCTION) || activeProfile.equals(ENV_SPI)) http .addFilter(casAuthenticationFilter()) .addFilterBefore(requestSingleLogoutFilter(), LogoutFilter.class) .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class) .logout() .logoutUrl("/dologout") .logoutSuccessUrl(applicationBaseUrl + "/j_spring_cas_security_logout") .invalidateHttpSession(true) .deleteCookies("JSESSIONID") .permitAll() .and() .exceptionHandling() .authenticationEntryPoint(casAuthenticationEntryPoint()) .and() .csrf().disable() .headers().frameOptions().disable(); } }
也感觉我的http config方法可以清理(此项目已从启动1.x天迁移过来)
更新:
有了Marco的评论,我得以找到解决方案。我创建了一个自定义类,该类扩展了CasAuthenticationPoint,该自定义类在所有重写的方法上调用super(...),仅公开用于操作的最终方法和受保护的方法(我仍然需要CAS来创建和编码服务以及重定向网址)。
private CommonAuthenticationEntryPoint commonAuthenticationEntryPoint() { CustomCasAuthenticationEntryPoint ep = new CustomCasAuthenticationEntryPoint(); ep.setLoginUrl(casServiceUrl + "/login"); ep.setServiceProperties(serviceProperties()); return new CommonAuthenticationEntryPoint(ep); }
然后是AutheticationEntryPoint:
public class CommonAuthenticationEntryPoint implements AuthenticationEntryPoint, InitializingBean { private final CustomCasAuthenticationEntryPoint customCasAuthenticationEntryPoint; public CommonAuthenticationEntryPoint(CustomCasAuthenticationEntryPoint customCasAuthenticationEntryPoint) { this.customCasAuthenticationEntryPoint = customCasAuthenticationEntryPoint; } @Override public void afterPropertiesSet() { customCasAuthenticationEntryPoint.afterPropertiesSet(); } @Override public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authenticationException) throws IOException { if (request.getParameter("cas") == null) response.sendRedirect("login"); else { final String urlEncodedService = customCasAuthenticationEntryPoint.createServiceUrl(request, response); final String redirectUrl = customCasAuthenticationEntryPoint.createRedirectUrl(urlEncodedService); customCasAuthenticationEntryPoint.preCommence(request, response); response.sendRedirect(redirectUrl); } } }
然后百里香中的按钮执行此操作:
<a class="btn btn-lg btn-default btn-block" th:href="@{${session.get('SPRING_SECURITY_SAVED_REQUEST').redirectUrl}(cas=true)}">
<img th:src="@{/favicon_192x192.png}" aria-hidden="true" alt="" id="org-sso"/> Organization CAS
</a>
我有一个Spring Boot 2.2应用程序,可使用组织的CAS实例对用户进行身份验证。当用户请求需要授权(例如,角色)时,spring sec cas集成(过滤器)开始...
CAS旨在作为中央服务,因此设置此流程有点奇怪。为了使CAS能够集成您需要的所有身份验证提供程序,最好始终使用CAS登录页面,并让它对照提供程序验证用户凭据:如果您允许“外部”用户访问,也可以使用CAS配置的身份验证提供程序。您是否尝试过这种方式?