diff --git a/zlt-uaa/src/main/java/com/central/oauth/config/SecurityConfig.java b/zlt-uaa/src/main/java/com/central/oauth/config/SecurityConfig.java index a869049aba6692241493c351f8f41c7f52511948..85f06694c869ffad59a7c3f631db497bd0751478 100644 --- a/zlt-uaa/src/main/java/com/central/oauth/config/SecurityConfig.java +++ b/zlt-uaa/src/main/java/com/central/oauth/config/SecurityConfig.java @@ -1,6 +1,7 @@ package com.central.oauth.config; import com.central.common.constant.SecurityConstants; +import com.central.oauth.filter.LoginProcessSetTenantFilter; import com.central.oauth.handler.OauthLogoutSuccessHandler; import com.central.oauth.mobile.MobileAuthenticationSecurityConfig; import com.central.oauth.openid.OpenIdAuthenticationSecurityConfig; @@ -19,7 +20,7 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; -import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutHandler; import javax.annotation.Resource; @@ -95,6 +96,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .and() .apply(mobileAuthenticationSecurityConfig) .and() + .addFilterBefore(new LoginProcessSetTenantFilter(), UsernamePasswordAuthenticationFilter.class) .csrf().disable() // 解决不允许显示在iframe的问题 .headers().frameOptions().disable().cacheControl(); diff --git a/zlt-uaa/src/main/java/com/central/oauth/controller/OAuth2Controller.java b/zlt-uaa/src/main/java/com/central/oauth/controller/OAuth2Controller.java index 4915dd9cc479be873a7e11bbf98f7b44e0648c81..be3880acea4ec4b36d1473f900b0b9825fe99ec2 100644 --- a/zlt-uaa/src/main/java/com/central/oauth/controller/OAuth2Controller.java +++ b/zlt-uaa/src/main/java/com/central/oauth/controller/OAuth2Controller.java @@ -100,6 +100,7 @@ public class OAuth2Controller { OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication); OAuth2AccessToken oAuth2AccessToken = authorizationServerTokenServices.createAccessToken(oAuth2Authentication); oAuth2Authentication.setAuthenticated(true); + TenantContextHolder.clear(); ResponseUtil.responseSucceed(objectMapper, response, oAuth2AccessToken); } catch (BadCredentialsException | InternalAuthenticationServiceException e) { exceptionHandler(response, badCredenbtialsMsg); diff --git a/zlt-uaa/src/main/java/com/central/oauth/filter/LoginProcessSetTenantFilter.java b/zlt-uaa/src/main/java/com/central/oauth/filter/LoginProcessSetTenantFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..5b7b0dcd9ec84516da86314e93464c26d20d559d --- /dev/null +++ b/zlt-uaa/src/main/java/com/central/oauth/filter/LoginProcessSetTenantFilter.java @@ -0,0 +1,66 @@ +package com.central.oauth.filter; + +import cn.hutool.core.util.ArrayUtil; +import com.alibaba.nacos.common.util.HttpMethod; +import com.central.common.constant.SecurityConstants; +import com.central.common.context.TenantContextHolder; +import org.springframework.security.web.savedrequest.DefaultSavedRequest; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 设置租户id过滤器 + * + * @author zlt + * @date 2020/3/29 + *

+ * Blog: https://blog.csdn.net/zlt2000 + * Github: https://github.com/zlt2000 + */ +public class LoginProcessSetTenantFilter extends OncePerRequestFilter { + private static final String SAVED_REQUEST = "SPRING_SECURITY_SAVED_REQUEST"; + + private RequestMatcher requiresAuthenticationRequestMatcher; + public LoginProcessSetTenantFilter() { + requiresAuthenticationRequestMatcher = new AntPathRequestMatcher(SecurityConstants.OAUTH_LOGIN_PRO_URL, HttpMethod.POST); + } + + /** + * 返回true代表不执行过滤器,false代表执行 + */ + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + if (requiresAuthentication(request)) { + return false; + } + return true; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + try { + DefaultSavedRequest savedRequest = (DefaultSavedRequest)request.getSession().getAttribute(SAVED_REQUEST); + if (savedRequest != null) { + String[] clientIds = savedRequest.getParameterValues("client_id"); + if (ArrayUtil.isNotEmpty(clientIds)) { + //保存租户id + TenantContextHolder.setTenant(clientIds[0]); + } + } + chain.doFilter(request, response); + } finally { + TenantContextHolder.clear(); + } + } + + private boolean requiresAuthentication(HttpServletRequest request) { + return requiresAuthenticationRequestMatcher.matches(request); + } +} diff --git a/zlt-uaa/src/main/java/com/central/oauth/filter/OauthTokenAspect.java b/zlt-uaa/src/main/java/com/central/oauth/filter/OauthTokenAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..3d587f1fed76386407d40fa0bde42b8a57edf6b0 --- /dev/null +++ b/zlt-uaa/src/main/java/com/central/oauth/filter/OauthTokenAspect.java @@ -0,0 +1,87 @@ +package com.central.oauth.filter; + +import com.central.common.constant.SecurityConstants; +import com.central.common.context.TenantContextHolder; +import com.central.common.model.Result; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.InsufficientAuthenticationException; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.util.OAuth2Utils; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.stereotype.Component; + +import java.security.Principal; +import java.util.Map; + +/** + * oauth-token拦截器 + * 1. 赋值租户 + * 2. 统一返回token格式 + * + * @author zlt + * @date 2020/3/29 + *

+ * Blog: https://blog.csdn.net/zlt2000 + * Github: https://github.com/zlt2000 + */ +@Slf4j +@Component +@Aspect +public class OauthTokenAspect { + @Around("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))") + public Object handleControllerMethod(ProceedingJoinPoint joinPoint) throws Throwable { + try { + Object[] args = joinPoint.getArgs(); + Principal principal = (Principal) args[0]; + if (!(principal instanceof Authentication)) { + throw new InsufficientAuthenticationException( + "There is no client authentication. Try adding an appropriate authentication filter."); + } + String clientId = getClientId(principal); + Map parameters = (Map) args[1]; + String grantType = parameters.get(OAuth2Utils.GRANT_TYPE); + + //保存租户id + TenantContextHolder.setTenant(clientId); + Object proceed = joinPoint.proceed(); + if (SecurityConstants.AUTHORIZATION_CODE.equals(grantType)) { + /* + 如果使用 @EnableOAuth2Sso 注解不能修改返回格式,否则授权码模式可以统一改 + 因为本项目的 sso-demo/ss-sso 里面使用了 @EnableOAuth2Sso 注解,所以这里就不修改授权码模式的token返回值了 + */ + return proceed; + } else { + ResponseEntity responseEntity = (ResponseEntity) proceed; + OAuth2AccessToken body = responseEntity.getBody(); + return ResponseEntity + .status(HttpStatus.OK) + .body(Result.succeed(body)); + } + } catch (Exception e) { + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(Result.failed(e.getMessage())); + } finally { + TenantContextHolder.clear(); + } + } + + private String getClientId(Principal principal) { + Authentication client = (Authentication) principal; + if (!client.isAuthenticated()) { + throw new InsufficientAuthenticationException("The client is not authenticated."); + } + String clientId = client.getName(); + if (client instanceof OAuth2Authentication) { + clientId = ((OAuth2Authentication) client).getOAuth2Request().getClientId(); + } + return clientId; + } +}