Skip to content

Commit

Permalink
feat: supports redirecting to a specified page after successful login (
Browse files Browse the repository at this point in the history
…#33)

### What this PR does?
登录成功后支持跳转到指定页面

/kind feature

Fixes #23 

```release-note
登录成功后支持跳转到指定页面
```
  • Loading branch information
guqing authored Jul 3, 2023
1 parent afa983f commit 3a4bf91
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 32 deletions.
69 changes: 46 additions & 23 deletions src/main/java/run/halo/oauth/Oauth2Authenticator.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import static org.apache.commons.lang3.StringUtils.defaultString;
import static run.halo.oauth.SocialServerOauth2AuthorizationRequestResolver.SOCIAL_CONNECTION;

import java.net.URI;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
Expand All @@ -18,6 +20,8 @@
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.server.authentication.OAuth2LoginAuthenticationWebFilter;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.server.DefaultServerRedirectStrategy;
import org.springframework.security.web.server.ServerRedirectStrategy;
import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
Expand Down Expand Up @@ -84,8 +88,6 @@ AuthenticationWebFilter createAuthenticationWebFilter() {
oauth2LoginConfiguration.getAuthenticationMatcher());
authenticationFilter.setServerAuthenticationConverter(
oauth2LoginConfiguration.getAuthenticationConverter());
authenticationFilter.setAuthenticationSuccessHandler(
oauth2LoginConfiguration.getAuthenticationSuccessHandler());
authenticationFilter.setAuthenticationFailureHandler(
oauth2LoginConfiguration.getAuthenticationFailureHandler());
authenticationFilter.setSecurityContextRepository(this.securityContextRepository);
Expand All @@ -94,7 +96,7 @@ AuthenticationWebFilter createAuthenticationWebFilter() {

class SocialLoginAuthenticationWebFilter extends OAuth2LoginAuthenticationWebFilter {

private ServerAuthenticationSuccessHandler authenticationSuccessHandler;
private final ServerRedirectStrategy redirectStrategy = new DefaultServerRedirectStrategy();
private final ServerOAuth2AuthorizedClientRepository authorizedClientRepository;

/**
Expand Down Expand Up @@ -130,13 +132,14 @@ protected Mono<Void> onAuthenticationSuccess(Authentication authentication,
.getAuthorizationRequest()
.getAdditionalParameters();
String socialConnection = (String) additionalParameters.get(SOCIAL_CONNECTION);
String redirectUri = (String) additionalParameters.get("binding_redirect_uri");
String bindingRedirectUri =
(String) additionalParameters.get("binding_redirect_uri");
String loginRedirectUri =
(String) additionalParameters.get("login_redirect_uri");
if (Boolean.parseBoolean(socialConnection)) {
// Social connect successfully, finish the process
return createConnection(webFilterExchange, authenticationResult)
.then(bindSuccessHandler(redirectUri)
.onAuthenticationSuccess(webFilterExchange, authentication)
);
.then(handleBindSuccessHandler(webFilterExchange, bindingRedirectUri));
}
return userConnectionService.isConnected(registrationId,
authenticationResult.getName())
Expand All @@ -146,7 +149,7 @@ protected Mono<Void> onAuthenticationSuccess(Authentication authentication,
return mappedToSystemUserAuthentication(registrationId,
authenticationResult)
.flatMap(result -> handleAuthenticationSuccess(result,
webFilterExchange));
webFilterExchange, loginRedirectUri));
}
// signup
OAuth2User principal = authenticationResult.getPrincipal();
Expand Down Expand Up @@ -188,33 +191,53 @@ private Mono<Void> createConnection(WebFilterExchange webFilterExchange,
.then();
}

private ServerAuthenticationSuccessHandler bindSuccessHandler(String redirectUri) {
if (StringUtils.isBlank(redirectUri)) {
return new RedirectServerAuthenticationSuccessHandler("/console/dashboard");
}
return new RedirectServerAuthenticationSuccessHandler(redirectUri);
}

@Override
public void setAuthenticationSuccessHandler(
ServerAuthenticationSuccessHandler authenticationSuccessHandler) {
super.setAuthenticationSuccessHandler(authenticationSuccessHandler);
this.authenticationSuccessHandler = authenticationSuccessHandler;
private Mono<Void> handleBindSuccessHandler(WebFilterExchange webFilterExchange,
String redirectUri) {
return getRedirectUri(webFilterExchange.getExchange(), redirectUri)
.defaultIfEmpty(URI.create("/console"))
.flatMap(
uri -> redirectStrategy.sendRedirect(webFilterExchange.getExchange(), uri));
}

Mono<Void> handleAuthenticationSuccess(Authentication authentication,
WebFilterExchange webFilterExchange) {
WebFilterExchange webFilterExchange,
String redirectUri) {
// Save the authentication result in the SecurityContext
ServerWebExchange exchange = webFilterExchange.getExchange();
SecurityContextImpl securityContext = new SecurityContextImpl();
securityContext.setAuthentication(authentication);
return securityContextRepository.save(exchange, securityContext)
.then(this.authenticationSuccessHandler.onAuthenticationSuccess(webFilterExchange,
authentication))
.then(authenticationSuccessRedirection(webFilterExchange,
redirectUri)
)
.contextWrite(
ReactiveSecurityContextHolder.withSecurityContext(Mono.just(securityContext)));
}

Mono<Void> authenticationSuccessRedirection(WebFilterExchange webFilterExchange,
String redirectUri) {
return getRedirectUri(webFilterExchange.getExchange(), redirectUri)
.defaultIfEmpty(URI.create("/console"))
.flatMap(uri ->
this.redirectStrategy.sendRedirect(webFilterExchange.getExchange(), uri)
)
.then();
}

Mono<URI> getRedirectUri(ServerWebExchange exchange, String redirectUriString) {
ServerHttpRequest request = exchange.getRequest();
if (StringUtils.isBlank(redirectUriString)) {
return Mono.empty();
}
URI redirectUri = URI.create(redirectUriString);
// Only redirect to the same host and port
if (redirectUri.getAuthority() != null
&& !redirectUri.getAuthority().equals(request.getURI().getAuthority())) {
return Mono.empty();
}
return Mono.just(redirectUri);
}

Mono<Authentication> mappedToSystemUserAuthentication(String registrationId,
Authentication authentication) {
return socialUserDetailsService.loadUserByUserId(registrationId,
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/run/halo/oauth/Oauth2LoginConfiguration.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package run.halo.oauth;

import java.net.URI;
import java.util.Optional;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authentication.DelegatingReactiveAuthenticationManager;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginReactiveAuthenticationManager;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.endpoint.ReactiveOAuth2AccessTokenResponseClient;
Expand Down Expand Up @@ -34,6 +40,7 @@
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoderFactory;
import org.springframework.security.web.server.DefaultServerRedirectStrategy;
import org.springframework.security.web.server.ServerRedirectStrategy;
import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationFailureHandler;
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
Expand All @@ -45,6 +52,8 @@
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import run.halo.app.extension.ReactiveExtensionClient;

/**
Expand All @@ -57,7 +66,6 @@
@Component
public final class Oauth2LoginConfiguration {
private final ReactiveAuthenticationManager authenticationManager;
private final ServerAuthenticationSuccessHandler authenticationSuccessHandler;
private final ServerAuthenticationFailureHandler authenticationFailureHandler;
private final ServerWebExchangeMatcher authenticationMatcher;
private final ServerOAuth2AuthorizedClientRepository authorizedClientRepository;
Expand All @@ -81,7 +89,6 @@ public Oauth2LoginConfiguration(ReactiveExtensionClient extensionClient) {

Initializer initializer = new Initializer();
this.authenticationManager = initializer.getAuthenticationManager();
this.authenticationSuccessHandler = initializer.getAuthenticationSuccessHandler();
this.authenticationFailureHandler = initializer.getAuthenticationFailureHandler();
this.authenticationMatcher = initializer.getAuthenticationMatcher();
this.authorizedClientRepository = initializer.getAuthorizedClientRepository();
Expand All @@ -104,13 +111,6 @@ public void setRequestCache(ServerRequestCache requestCache) {

class Initializer {

ServerAuthenticationSuccessHandler getAuthenticationSuccessHandler() {
RedirectServerAuthenticationSuccessHandler handler =
new RedirectServerAuthenticationSuccessHandler("/console/dashboard");
handler.setRequestCache(requestCache);
return handler;
}

ServerAuthenticationFailureHandler getAuthenticationFailureHandler() {
return new RedirectServerAuthenticationFailureHandler("/console/login?error");
}
Expand Down

0 comments on commit 3a4bf91

Please sign in to comment.