Spring OAuth2 不会在表单登录时重定向回客户端
Posted
技术标签:
【中文标题】Spring OAuth2 不会在表单登录时重定向回客户端【英文标题】:Spring OAuth2 not redirecting back to client on form login 【发布时间】:2015-03-27 16:31:47 【问题描述】:我正在使用 OAuth2 开发示例 Spring Boot 应用程序。问题是托管在localhost:8080
上的客户端调用https://localhost:8443/oauth/authorize
以授权自己(隐式授权类型),但由于/oauth/authorize
要求用户进行身份验证,因此它们被重定向到https://localhost:8443/login
的登录页面。
这是意料之中的,但是当用户登陆登录页面时,包括redirect_uri在内的所有查询字符串都丢失了。用户登录后被重定向到https://localhost:8443
,而不是http://localhost:8080
指定的redirect_uri。
有没有办法让用户在使用服务器的登录表单登录后重定向回客户端?我在我的配置中遗漏了什么吗?我可以根据需要发布更多内容。
授权请求如下:https://localhost:8443/oauth/authorize?response_type=token&state=6c2bb162-0f26-4caa-abbe-b65f7e5c6a2e&redirect_uri=http%3A%2F%2Flocalhost%3A8080&client_id=admin
安全配置:
@Configuration
public static class WebSecurityConfig extends WebSecurityConfigurerAdapter
private final Logger log = LoggerFactory.getLogger(WebSecurityConfig.class);
@Override
public void configure(WebSecurity web) throws Exception
web.ignoring().antMatchers("/resources/**");
@SuppressWarnings("deprecation")
@Override
protected void configure(HttpSecurity http) throws Exception
http
.requestMatchers()
.antMatchers("/**")
.and()
.addFilterAfter(new CsrfCookieGeneratorFilter(), CsrfFilter.class)
.exceptionHandling()
.accessDeniedPage("/login?authorization_error=true")
.and()
.authorizeRequests()
.antMatchers("/resources/**", "/csrf").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("j_username")
.passwordParameter("j_password")
.defaultSuccessUrl("/", false)
.failureUrl("/login?authentication_error=true")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID", "CSRF-TOKEN")
.permitAll()
.and()
.headers()
.frameOptions()
.disable();
OAuthConfig:
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter
@Inject
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Bean
public TokenStore tokenStore()
return new InMemoryTokenStore();
@Primary
@Bean
public ResourceServerTokenServices tokenServices()
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(tokenStore());
return tokenServices;
@Bean
public ApprovalStore approvalStore() throws Exception
TokenApprovalStore approvalStore = new TokenApprovalStore();
approvalStore.setTokenStore(tokenStore());
return approvalStore;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception
clients
.inMemory()
.withClient("read-only")
.secret("readme")
.resourceIds(RESOURCE_ID)
.authorizedGrantTypes("implicit", "password", "refresh_token")
.authorities(Constant.USER)
.scopes("read")
.autoApprove(true)
.redirectUris("https://localhost:8443")
.and()
.withClient("admin")
.secret("admin")
.resourceIds(RESOURCE_ID)
.authorizedGrantTypes("implicit", "password", "refresh_token")
.authorities(Constant.USER, Constant.ADMIN)
.scopes("read", "write")
.autoApprove(true)
.redirectUris("https://localhost:8443", "http://localhost:8080")
.and()
.withClient("super-admin")
.secret("super")
.resourceIds(RESOURCE_ID)
.authorizedGrantTypes("implicit", "password", "refresh_token")
.authorities(Constant.USER, Constant.ADMIN)
.scopes("read", "write", "delete")
.redirectUris("https://localhost:8443");
@Override
public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception
configurer
.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
@Override
public void configure(AuthorizationServerSecurityConfigurer security)
throws Exception
security.realm("hubble/client");
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception
resources.resourceId(RESOURCE_ID);
@Override
public void configure(HttpSecurity http) throws Exception
http
.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll()
.antMatchers(HttpMethod.GET, "/api/**").access("#oauth2.hasScope('read')")
.antMatchers(HttpMethod.POST, "/api/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.PATCH, "/api/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.PUT, "/api/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.DELETE, "/api/**").access("#oauth2.hasScope('delete')")
.antMatchers("/api/**").access("hasRole('" + Constant.USER + "')")
.and()
.anonymous().authorities(Constant.ANONYMOUS)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
protected static class MethodSecurityConfig extends GlobalMethodSecurityConfiguration
@Override
protected MethodSecurityExpressionHandler createExpressionHandler()
OAuth2MethodSecurityExpressionHandler methodHandler = new OAuth2MethodSecurityExpressionHandler();
return methodHandler;
【问题讨论】:
它对我有用(我从不使用defaultSuccessUrl()
,但我没有看到任何明显的问题)。你能发布一个完整项目的链接吗?
感谢@DaveSyer 观看!我尝试了 defaultSuccessUrl() 希望它能解决我的问题,但不管有没有骰子。如果我使用基本身份验证而不是表单登录来保护 /oauth/**,它就可以工作。明天我会尝试将项目放到 github 上并提供链接。
嗨,这个成功了吗?我有同样的问题。
您好,也有同样的问题。 OP 或@pborbas 你解决了吗?
@J.Marciniak 我添加了答案。
【参考方案1】:
此问题仅出现在表单身份验证中,与 OAuth 无关。 org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint 有一个 buildRedirectUrlToLoginPage 方法创建登录 URL 并忘记查询字符串。
目前我们通过解决方法解决了这个问题。
-
我们没有将用户重定向到授权网址,而是直接重定向到登录页面。
登录页面有一个控制器,用于检查用户是否已登录,如果已登录,它会使用 redirect_uri(如果存在)或默认应用程序 url 作为 redirect_uri 重定向到授权 url。
从这里开始,redirect_uri 由授权 url 正确处理。
第 2 步中的 LoginController 示例如下所示:
@Controller
@RequestMapping(value = "/login")
public class LoginController
@RequestMapping(method = RequestMethod.GET)
public String getPage(HttpServletRequest request, HttpServletResponse response, Principal principal)
throws IOException
if (principal != null) //depends on your security config, maybe you want to check the security context instead if you allow anonym access
String redirect_uri = request.getParameter("redirect_uri");
//here you must get all the other attributes thats needed for the authorize url
if (redirect_uri == null)
redirect_uri = "https://your.default.app.url";
return "redirect:https://localhost:8443/oauth/authorize?response_type=token&state=6c2bb162-0f26-4caa-abbe-b65f7e5c6a2e&client_id=admin&redirect_uri=" + URLEncoder.encode(redirect_uri, "UTF-8");
return "login";
【讨论】:
授权不是应该由隐式处理而不是硬编码吗?我总是被重定向到成功登录时登录以上是关于Spring OAuth2 不会在表单登录时重定向回客户端的主要内容,如果未能解决你的问题,请参考以下文章
Spring Cloud OAuth2:身份验证后再次重定向到登录页面,就像使用表单登录时未经身份验证一样
Spring Social:当服务器在代理后面时重定向 url