This commit is contained in:
		
							parent
							
								
									c3c02a9473
								
							
						
					
					
						commit
						e3aa1b0fd0
					
				| 
						 | 
					@ -53,6 +53,21 @@
 | 
				
			||||||
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
 | 
					            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
 | 
				
			||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc -->
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.dev33</groupId>
 | 
				
			||||||
 | 
					            <artifactId>sa-token-spring-boot-starter</artifactId>
 | 
				
			||||||
 | 
					            <version>1.37.0</version>
 | 
				
			||||||
 | 
					            <exclusions>
 | 
				
			||||||
 | 
					                <exclusion>
 | 
				
			||||||
 | 
					                    <!-- 配置冲突,需要排除   -->
 | 
				
			||||||
 | 
					                    <groupId>org.springframework.boot</groupId>
 | 
				
			||||||
 | 
					                    <artifactId>spring-boot-starter-web</artifactId>
 | 
				
			||||||
 | 
					                </exclusion>
 | 
				
			||||||
 | 
					            </exclusions>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- JWT库 -->
 | 
					        <!-- JWT库 -->
 | 
				
			||||||
        <dependency>
 | 
					        <dependency>
 | 
				
			||||||
            <groupId>com.nimbusds</groupId>
 | 
					            <groupId>com.nimbusds</groupId>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					package com.recovery.admin.boot.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.dev33.satoken.context.SaHolder;
 | 
				
			||||||
 | 
					import cn.dev33.satoken.filter.SaServletFilter;
 | 
				
			||||||
 | 
					import cn.dev33.satoken.same.SaSameUtil;
 | 
				
			||||||
 | 
					import cn.dev33.satoken.util.SaResult;
 | 
				
			||||||
 | 
					import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Bean;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Sa-Token 权限认证 配置类
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Configuration
 | 
				
			||||||
 | 
					@Slf4j
 | 
				
			||||||
 | 
					public class SaTokenConfigure implements WebMvcConfigurer {
 | 
				
			||||||
 | 
					    // 注册 Sa-Token 全局过滤器
 | 
				
			||||||
 | 
					    @Bean
 | 
				
			||||||
 | 
					    public SaServletFilter getSaServletFilter() {
 | 
				
			||||||
 | 
					        log.info("校验是否是网关转发请求:====================");
 | 
				
			||||||
 | 
					        return new SaServletFilter()
 | 
				
			||||||
 | 
					                .addInclude("/**")
 | 
				
			||||||
 | 
					                .addExclude("/favicon.ico")
 | 
				
			||||||
 | 
					                .setAuth(obj -> {
 | 
				
			||||||
 | 
					                    // 校验 Same-Token 身份凭证     —— 以下两句代码可简化为:SaSameUtil.checkCurrentRequestToken();
 | 
				
			||||||
 | 
					                    String token = SaHolder.getRequest().getHeader(SaSameUtil.SAME_TOKEN);
 | 
				
			||||||
 | 
					                    SaSameUtil.checkToken(token);
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .setError(e -> {
 | 
				
			||||||
 | 
					                    return SaResult.error(e.getMessage());
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,15 @@
 | 
				
			||||||
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
 | 
					            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
 | 
				
			||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc -->
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.dev33</groupId>
 | 
				
			||||||
 | 
					            <artifactId>sa-token-spring-boot-starter</artifactId>
 | 
				
			||||||
 | 
					            <version>1.37.0</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <dependency>
 | 
					        <dependency>
 | 
				
			||||||
            <groupId>org.springframework.cloud</groupId>
 | 
					            <groupId>org.springframework.cloud</groupId>
 | 
				
			||||||
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
 | 
					            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
 | 
				
			||||||
| 
						 | 
					@ -46,25 +55,13 @@
 | 
				
			||||||
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
 | 
					            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
 | 
				
			||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <dependency>
 | 
					
 | 
				
			||||||
            <groupId>org.springframework.security</groupId>
 | 
					 | 
				
			||||||
            <artifactId>spring-security-oauth2-jose</artifactId>
 | 
					 | 
				
			||||||
        </dependency>
 | 
					 | 
				
			||||||
        <dependency>
 | 
					        <dependency>
 | 
				
			||||||
            <groupId>com.recovery</groupId>
 | 
					            <groupId>com.recovery</groupId>
 | 
				
			||||||
            <artifactId>common-web</artifactId>
 | 
					            <artifactId>common-web</artifactId>
 | 
				
			||||||
            <version>${hoe-version}</version>
 | 
					            <version>${hoe-version}</version>
 | 
				
			||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
        <!-- OAuth2 认证服务器-->
 | 
					 | 
				
			||||||
        <dependency>
 | 
					 | 
				
			||||||
            <groupId>org.springframework.security.oauth.boot</groupId>
 | 
					 | 
				
			||||||
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
 | 
					 | 
				
			||||||
        </dependency>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <dependency>
 | 
					 | 
				
			||||||
            <groupId>org.springframework.security</groupId>
 | 
					 | 
				
			||||||
            <artifactId>spring-security-oauth2-jose</artifactId>
 | 
					 | 
				
			||||||
        </dependency>
 | 
					 | 
				
			||||||
    </dependencies>
 | 
					    </dependencies>
 | 
				
			||||||
    <build>
 | 
					    <build>
 | 
				
			||||||
        <plugins>
 | 
					        <plugins>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,107 +0,0 @@
 | 
				
			||||||
package com.recovery.auth.comm.exception;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.recovery.common.base.result.ApiResult;
 | 
					 | 
				
			||||||
import com.recovery.common.base.result.ResultCode;
 | 
					 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					 | 
				
			||||||
import org.springframework.core.annotation.Order;
 | 
					 | 
				
			||||||
import org.springframework.http.HttpStatus;
 | 
					 | 
				
			||||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
 | 
					 | 
				
			||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.NoSuchClientException;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.ResponseStatus;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * @author: 
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
@RestControllerAdvice
 | 
					 | 
				
			||||||
@Slf4j
 | 
					 | 
				
			||||||
@Order(-1)
 | 
					 | 
				
			||||||
public class AuthExceptionHandler {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 用户不存在
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param e
 | 
					 | 
				
			||||||
     * @return
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @ResponseStatus(HttpStatus.BAD_REQUEST)
 | 
					 | 
				
			||||||
    @ExceptionHandler(UsernameNotFoundException.class)
 | 
					 | 
				
			||||||
    public ApiResult handleUsernameNotFoundException(UsernameNotFoundException e) {
 | 
					 | 
				
			||||||
        log.error("错误信息:{}", e.getMessage(),e);
 | 
					 | 
				
			||||||
        return ApiResult.failed(ResultCode.USER_NOT_EXIST);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 用户名和密码异常
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param e
 | 
					 | 
				
			||||||
     * @return
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @ResponseStatus(HttpStatus.BAD_REQUEST)
 | 
					 | 
				
			||||||
    @ExceptionHandler(InvalidGrantException.class)
 | 
					 | 
				
			||||||
    public ApiResult handleInvalidGrantException(InvalidGrantException e) {
 | 
					 | 
				
			||||||
        log.error("错误信息:{}", e.getMessage(),e);
 | 
					 | 
				
			||||||
        return ApiResult.failed(ResultCode.USERNAME_OR_PASSWORD_ERROR);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 用户名和密码异常
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param e
 | 
					 | 
				
			||||||
     * @return
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @ResponseStatus(HttpStatus.BAD_REQUEST)
 | 
					 | 
				
			||||||
    @ExceptionHandler(InvalidClientException.class)
 | 
					 | 
				
			||||||
    public ApiResult handleInvalidGrantException(InvalidClientException e) {
 | 
					 | 
				
			||||||
        log.error("错误信息:{}", e.getMessage(),e);
 | 
					 | 
				
			||||||
        return ApiResult.failed(ResultCode.CLIENT_AUTHENTICATION_FAILED);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 账户异常(禁用、锁定、过期)
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param e
 | 
					 | 
				
			||||||
     * @return
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @ResponseStatus(HttpStatus.BAD_REQUEST)
 | 
					 | 
				
			||||||
    @ExceptionHandler({InternalAuthenticationServiceException.class})
 | 
					 | 
				
			||||||
    public ApiResult handleInternalAuthenticationServiceException(InternalAuthenticationServiceException e) {
 | 
					 | 
				
			||||||
        log.error("错误信息:{}", e.getMessage(),e);
 | 
					 | 
				
			||||||
        return ApiResult.failed(e.getMessage());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * token 无效或已过期
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param e
 | 
					 | 
				
			||||||
     * @return
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @ResponseStatus(HttpStatus.BAD_REQUEST)
 | 
					 | 
				
			||||||
    @ExceptionHandler({InvalidTokenException.class})
 | 
					 | 
				
			||||||
    public ApiResult handleInvalidTokenExceptionException(InvalidTokenException e) {
 | 
					 | 
				
			||||||
        log.error("错误信息:{}", e.getMessage(),e);
 | 
					 | 
				
			||||||
        return ApiResult.failed(e.getMessage());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * token 无效或已过期
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param e
 | 
					 | 
				
			||||||
     * @return
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @ResponseStatus(HttpStatus.BAD_REQUEST)
 | 
					 | 
				
			||||||
    @ExceptionHandler({NoSuchClientException.class})
 | 
					 | 
				
			||||||
    public ApiResult noSuchClientException(NoSuchClientException e) {
 | 
					 | 
				
			||||||
        log.error("错误信息:{}", e.getMessage(),e);
 | 
					 | 
				
			||||||
        return ApiResult.failed(e.getMessage());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,36 +0,0 @@
 | 
				
			||||||
package com.recovery.auth.comm.utils;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import cn.hutool.core.util.StrUtil;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.recovery.common.base.constant.SecurityConstants;
 | 
					 | 
				
			||||||
import org.apache.logging.log4j.util.Strings;
 | 
					 | 
				
			||||||
import org.springframework.web.context.request.RequestContextHolder;
 | 
					 | 
				
			||||||
import org.springframework.web.context.request.ServletRequestAttributes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.servlet.http.HttpServletRequest;
 | 
					 | 
				
			||||||
import java.nio.charset.StandardCharsets;
 | 
					 | 
				
			||||||
import java.util.Base64;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * @author: 
 | 
					 | 
				
			||||||
 * @date: 2022/5/23
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class CommonUtils {
 | 
					 | 
				
			||||||
    public static String getOAuth2ClientId() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        String clientId = request.getParameter(SecurityConstants.CLIENT_ID_KEY);
 | 
					 | 
				
			||||||
        if (StrUtil.isNotBlank(clientId)) {
 | 
					 | 
				
			||||||
            return clientId;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        String basic = request.getHeader(SecurityConstants.AUTHORIZATION_KEY);
 | 
					 | 
				
			||||||
        if (StrUtil.isNotBlank(basic) && basic.startsWith(SecurityConstants.BASIC_PREFIX)) {
 | 
					 | 
				
			||||||
            basic = basic.replace(SecurityConstants.BASIC_PREFIX, Strings.EMPTY);
 | 
					 | 
				
			||||||
            String basicPlainText = new String(Base64.getDecoder().decode(basic.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
 | 
					 | 
				
			||||||
            clientId = basicPlainText.split(":")[0];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return clientId;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,138 +0,0 @@
 | 
				
			||||||
package com.recovery.auth.config;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import cn.hutool.core.collection.CollectionUtil;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.recovery.auth.security.details.client.ClientDetailsServiceImpl;
 | 
					 | 
				
			||||||
import com.recovery.auth.security.details.user.SysUserDetails;
 | 
					 | 
				
			||||||
import lombok.RequiredArgsConstructor;
 | 
					 | 
				
			||||||
import lombok.SneakyThrows;
 | 
					 | 
				
			||||||
import org.springframework.context.annotation.Bean;
 | 
					 | 
				
			||||||
import org.springframework.context.annotation.Configuration;
 | 
					 | 
				
			||||||
import org.springframework.core.io.ClassPathResource;
 | 
					 | 
				
			||||||
import org.springframework.security.authentication.AuthenticationManager;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.TokenGranter;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.security.KeyPair;
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.Arrays;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
import java.util.Map;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Created with IntelliJ IDEA.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author
 | 
					 | 
				
			||||||
 * @date: 2021/11/24
 | 
					 | 
				
			||||||
 * @description:
 | 
					 | 
				
			||||||
 * @modifiedBy:
 | 
					 | 
				
			||||||
 * @version: 1.0
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
@Configuration
 | 
					 | 
				
			||||||
@EnableAuthorizationServer
 | 
					 | 
				
			||||||
@RequiredArgsConstructor
 | 
					 | 
				
			||||||
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private final AuthenticationManager authenticationManager;
 | 
					 | 
				
			||||||
    private final ClientDetailsServiceImpl clientDetailsService;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * OAuth2客户端
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    @SneakyThrows
 | 
					 | 
				
			||||||
    public void configure(ClientDetailsServiceConfigurer clients) {
 | 
					 | 
				
			||||||
        clients.withClientDetails(clientDetailsService);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
 | 
					 | 
				
			||||||
        // Token增强
 | 
					 | 
				
			||||||
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
 | 
					 | 
				
			||||||
        List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
 | 
					 | 
				
			||||||
        tokenEnhancers.add(tokenEnhancer());
 | 
					 | 
				
			||||||
        tokenEnhancers.add(jwtAccessTokenConverter());
 | 
					 | 
				
			||||||
        tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 获取原有默认授权模式(授权码模式、密码模式、客户端模式、简化模式)的授权者
 | 
					 | 
				
			||||||
        List<TokenGranter> granterList = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(granterList);
 | 
					 | 
				
			||||||
        endpoints
 | 
					 | 
				
			||||||
                .authenticationManager(authenticationManager)
 | 
					 | 
				
			||||||
                .accessTokenConverter(jwtAccessTokenConverter())
 | 
					 | 
				
			||||||
                .tokenEnhancer(tokenEnhancerChain)
 | 
					 | 
				
			||||||
                .tokenGranter(compositeTokenGranter)
 | 
					 | 
				
			||||||
                .reuseRefreshTokens(true)
 | 
					 | 
				
			||||||
                .tokenServices(tokenServices(endpoints))
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public DefaultTokenServices tokenServices(AuthorizationServerEndpointsConfigurer endpoints) {
 | 
					 | 
				
			||||||
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
 | 
					 | 
				
			||||||
        List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
 | 
					 | 
				
			||||||
        tokenEnhancers.add(tokenEnhancer());
 | 
					 | 
				
			||||||
        tokenEnhancers.add(jwtAccessTokenConverter());
 | 
					 | 
				
			||||||
        tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        DefaultTokenServices tokenServices = new DefaultTokenServices();
 | 
					 | 
				
			||||||
        tokenServices.setTokenStore(endpoints.getTokenStore());
 | 
					 | 
				
			||||||
        tokenServices.setSupportRefreshToken(true);
 | 
					 | 
				
			||||||
        tokenServices.setClientDetailsService(clientDetailsService);
 | 
					 | 
				
			||||||
        tokenServices.setTokenEnhancer(tokenEnhancerChain);
 | 
					 | 
				
			||||||
        return tokenServices;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * JWT内容增强
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Bean
 | 
					 | 
				
			||||||
    public TokenEnhancer tokenEnhancer() {
 | 
					 | 
				
			||||||
        return (accessToken, authentication) -> {
 | 
					 | 
				
			||||||
            Map<String, Object> additionalInfo = CollectionUtil.newHashMap();
 | 
					 | 
				
			||||||
            Object principal = authentication.getUserAuthentication().getPrincipal();
 | 
					 | 
				
			||||||
            if (principal instanceof SysUserDetails){
 | 
					 | 
				
			||||||
                SysUserDetails sysUserDetails = (SysUserDetails) principal;
 | 
					 | 
				
			||||||
                additionalInfo.put("userId", sysUserDetails.getUserId());
 | 
					 | 
				
			||||||
                additionalInfo.put("username", sysUserDetails.getUsername());
 | 
					 | 
				
			||||||
                ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return accessToken;
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 使用非对称加密算法对token签名
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Bean
 | 
					 | 
				
			||||||
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
 | 
					 | 
				
			||||||
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
 | 
					 | 
				
			||||||
        converter.setKeyPair(keyPair());
 | 
					 | 
				
			||||||
        return converter;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 密钥库中获取密钥对(公钥+私钥)
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Bean
 | 
					 | 
				
			||||||
    public KeyPair keyPair() {
 | 
					 | 
				
			||||||
        KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "afd123".toCharArray());
 | 
					 | 
				
			||||||
        KeyPair keyPair = factory.getKeyPair("jwt", "afd123".toCharArray());
 | 
					 | 
				
			||||||
        return keyPair;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					package com.recovery.auth.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.dev33.satoken.context.SaHolder;
 | 
				
			||||||
 | 
					import cn.dev33.satoken.filter.SaServletFilter;
 | 
				
			||||||
 | 
					import cn.dev33.satoken.same.SaSameUtil;
 | 
				
			||||||
 | 
					import cn.dev33.satoken.util.SaResult;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Bean;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Sa-Token 权限认证 配置类
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Configuration
 | 
				
			||||||
 | 
					public class SaTokenConfigure implements WebMvcConfigurer {
 | 
				
			||||||
 | 
					    // 注册 Sa-Token 全局过滤器
 | 
				
			||||||
 | 
					    @Bean
 | 
				
			||||||
 | 
					    public SaServletFilter getSaServletFilter() {
 | 
				
			||||||
 | 
					        return new SaServletFilter()
 | 
				
			||||||
 | 
					                .addInclude("/**")
 | 
				
			||||||
 | 
					                .addExclude("/favicon.ico")
 | 
				
			||||||
 | 
					                .setAuth(obj -> {
 | 
				
			||||||
 | 
					                    // 校验 Same-Token 身份凭证     —— 以下两句代码可简化为:SaSameUtil.checkCurrentRequestToken();
 | 
				
			||||||
 | 
					                    String token = SaHolder.getRequest().getHeader(SaSameUtil.SAME_TOKEN);
 | 
				
			||||||
 | 
					                    SaSameUtil.checkToken(token);
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .setError(e -> {
 | 
				
			||||||
 | 
					                    return SaResult.error(e.getMessage());
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,85 +0,0 @@
 | 
				
			||||||
package com.recovery.auth.config;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import lombok.RequiredArgsConstructor;
 | 
					 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					 | 
				
			||||||
import org.springframework.context.annotation.Bean;
 | 
					 | 
				
			||||||
import org.springframework.context.annotation.Configuration;
 | 
					 | 
				
			||||||
import org.springframework.security.authentication.AuthenticationManager;
 | 
					 | 
				
			||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
 | 
					 | 
				
			||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 | 
					 | 
				
			||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 | 
					 | 
				
			||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 | 
					 | 
				
			||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 | 
					 | 
				
			||||||
import org.springframework.security.core.userdetails.UserDetailsService;
 | 
					 | 
				
			||||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
 | 
					 | 
				
			||||||
import org.springframework.security.crypto.password.PasswordEncoder;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Created with IntelliJ IDEA.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author:
 | 
					 | 
				
			||||||
 * @date: 2021/11/24
 | 
					 | 
				
			||||||
 * @description:
 | 
					 | 
				
			||||||
 * @modifiedBy:
 | 
					 | 
				
			||||||
 * @version: 1.0
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
@Configuration
 | 
					 | 
				
			||||||
@EnableWebSecurity
 | 
					 | 
				
			||||||
@Slf4j
 | 
					 | 
				
			||||||
@RequiredArgsConstructor
 | 
					 | 
				
			||||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private final UserDetailsService sysUserDetailsService;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    protected void configure(HttpSecurity http) throws Exception {
 | 
					 | 
				
			||||||
        http
 | 
					 | 
				
			||||||
                .authorizeRequests().antMatchers("/api/oauth/**").permitAll()
 | 
					 | 
				
			||||||
                .anyRequest().authenticated()
 | 
					 | 
				
			||||||
                .and()
 | 
					 | 
				
			||||||
                .httpBasic()
 | 
					 | 
				
			||||||
                .and()
 | 
					 | 
				
			||||||
                .csrf().disable();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 认证管理对象
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @return
 | 
					 | 
				
			||||||
     * @throws Exception
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Bean
 | 
					 | 
				
			||||||
    public AuthenticationManager authenticationManagerBean() throws Exception {
 | 
					 | 
				
			||||||
        return super.authenticationManagerBean();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 添加自定义认证器
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param auth
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
 | 
					 | 
				
			||||||
        auth.authenticationProvider(daoAuthenticationProvider());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 设置默认的用户名密码认证授权提供者
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @return
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Bean
 | 
					 | 
				
			||||||
    public DaoAuthenticationProvider daoAuthenticationProvider() {
 | 
					 | 
				
			||||||
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
 | 
					 | 
				
			||||||
        provider.setUserDetailsService(sysUserDetailsService);
 | 
					 | 
				
			||||||
        provider.setPasswordEncoder(passwordEncoder());
 | 
					 | 
				
			||||||
        provider.setHideUserNotFoundExceptions(false); // 是否隐藏用户不存在异常,默认:true-隐藏;false-抛出异常;
 | 
					 | 
				
			||||||
        return provider;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Bean
 | 
					 | 
				
			||||||
    public PasswordEncoder passwordEncoder() {
 | 
					 | 
				
			||||||
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,25 +1,25 @@
 | 
				
			||||||
package com.recovery.auth.controller;
 | 
					package com.recovery.auth.controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.nimbusds.jose.jwk.JWKSet;
 | 
					import cn.dev33.satoken.stp.SaTokenInfo;
 | 
				
			||||||
import com.nimbusds.jose.jwk.RSAKey;
 | 
					import cn.dev33.satoken.stp.StpUtil;
 | 
				
			||||||
 | 
					import cn.dev33.satoken.util.SaResult;
 | 
				
			||||||
 | 
					import com.recovery.auth.exception.BusinessException;
 | 
				
			||||||
 | 
					import com.recovery.auth.feign.UserFeignClient;
 | 
				
			||||||
import com.recovery.auth.security.details.user.JwtAuthenticationRequest;
 | 
					import com.recovery.auth.security.details.user.JwtAuthenticationRequest;
 | 
				
			||||||
import com.recovery.auth.service.AuthService;
 | 
					import com.recovery.auth.service.AuthService;
 | 
				
			||||||
 | 
					import com.recovery.common.base.dto.UserAuthDTO;
 | 
				
			||||||
 | 
					import com.recovery.common.base.dto.UserAuthorityDto;
 | 
				
			||||||
import com.recovery.common.base.result.ApiResult;
 | 
					import com.recovery.common.base.result.ApiResult;
 | 
				
			||||||
 | 
					import com.recovery.common.base.result.ResultCode;
 | 
				
			||||||
import lombok.AllArgsConstructor;
 | 
					import lombok.AllArgsConstructor;
 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
 | 
					import org.springframework.util.StringUtils;
 | 
				
			||||||
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
 | 
					 | 
				
			||||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.*;
 | 
					import org.springframework.web.bind.annotation.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Resource;
 | 
					import javax.annotation.Resource;
 | 
				
			||||||
import javax.servlet.http.HttpServletRequest;
 | 
					import javax.servlet.http.HttpServletRequest;
 | 
				
			||||||
import java.security.KeyPair;
 | 
					 | 
				
			||||||
import java.security.Principal;
 | 
					 | 
				
			||||||
import java.security.interfaces.RSAPublicKey;
 | 
					 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.Map;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @author: 
 | 
					 * @author: 
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,8 @@ public class AuthController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Resource
 | 
					    @Resource
 | 
				
			||||||
    AuthService authService;
 | 
					    AuthService authService;
 | 
				
			||||||
 | 
					    @Resource
 | 
				
			||||||
 | 
					    UserFeignClient userFeignClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @PostMapping("/token")
 | 
					    @PostMapping("/token")
 | 
				
			||||||
    public ApiResult postAccessToken(@RequestBody JwtAuthenticationRequest authenticationRequest, HttpServletRequest request){
 | 
					    public ApiResult postAccessToken(@RequestBody JwtAuthenticationRequest authenticationRequest, HttpServletRequest request){
 | 
				
			||||||
| 
						 | 
					@ -46,6 +48,32 @@ public class AuthController {
 | 
				
			||||||
        return ApiResult.ok(map);
 | 
					        return ApiResult.ok(map);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @GetMapping("/doLogin")
 | 
				
			||||||
 | 
					    public SaResult doLogin(@RequestBody JwtAuthenticationRequest authenticationRequest) {
 | 
				
			||||||
 | 
					        if(StringUtils.isEmpty(authenticationRequest.getUsername())){
 | 
				
			||||||
 | 
					            throw new BusinessException("账户不能为空");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(StringUtils.isEmpty(authenticationRequest.getPassword())){
 | 
				
			||||||
 | 
					            throw new BusinessException("密码不能为空");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ApiResult<UserAuthDTO> result = userFeignClient.getUserByUsername(authenticationRequest.getUsername());
 | 
				
			||||||
 | 
					        UserAuthDTO userDetails = new UserAuthDTO();
 | 
				
			||||||
 | 
					        if (ResultCode.SUCCESS.getCode().equals(result.getCode())) {
 | 
				
			||||||
 | 
					            userDetails = result.getData();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对
 | 
				
			||||||
 | 
					        if (userDetails.getUserName().equals(authenticationRequest.getUsername()) && userDetails.getPassword().equals(authenticationRequest.getPassword())) {
 | 
				
			||||||
 | 
					            log.info("密码校验成功!");
 | 
				
			||||||
 | 
					            StpUtil.login(userDetails.getUserName());
 | 
				
			||||||
 | 
					        }else {
 | 
				
			||||||
 | 
					            return SaResult.error("密码错误");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 第3步,返回给前端
 | 
				
			||||||
 | 
					        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
 | 
				
			||||||
 | 
					        return SaResult.ok("登录成功").setData(tokenInfo);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//    @GetMapping("/public-key")
 | 
					//    @GetMapping("/public-key")
 | 
				
			||||||
//    public Map<String, Object> getPublicKey() {
 | 
					//    public Map<String, Object> getPublicKey() {
 | 
				
			||||||
//       //单例模式
 | 
					//       //单例模式
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,43 +0,0 @@
 | 
				
			||||||
package com.recovery.auth.security.details.client;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.recovery.common.base.enums.PasswordEncoderTypeEnum;
 | 
					 | 
				
			||||||
import lombok.RequiredArgsConstructor;
 | 
					 | 
				
			||||||
import org.springframework.cache.annotation.Cacheable;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.ClientDetails;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.ClientDetailsService;
 | 
					 | 
				
			||||||
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
 | 
					 | 
				
			||||||
import org.springframework.stereotype.Service;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Created with IntelliJ IDEA.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author: AI码师
 | 
					 | 
				
			||||||
 * @date: 2021/11/24
 | 
					 | 
				
			||||||
 * @description:
 | 
					 | 
				
			||||||
 * @modifiedBy:
 | 
					 | 
				
			||||||
 * @version: 1.0
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
@Service
 | 
					 | 
				
			||||||
@RequiredArgsConstructor
 | 
					 | 
				
			||||||
public class ClientDetailsServiceImpl implements ClientDetailsService {
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    @Cacheable(cacheNames = "auth", key = "'oauth-client:'+#clientId")
 | 
					 | 
				
			||||||
    public ClientDetails loadClientByClientId(String clientId) {
 | 
					 | 
				
			||||||
        // 后面通过feign从管理端获取,目前写死
 | 
					 | 
				
			||||||
        BaseClientDetails clientDetails = new BaseClientDetails(
 | 
					 | 
				
			||||||
                "hoe",
 | 
					 | 
				
			||||||
                "",
 | 
					 | 
				
			||||||
                "all",
 | 
					 | 
				
			||||||
                "password,client_credentials,refresh_token,authorization_code",
 | 
					 | 
				
			||||||
                "",
 | 
					 | 
				
			||||||
                "http://www.baidu.com"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        clientDetails.setClientSecret(PasswordEncoderTypeEnum.NOOP.getPrefix() + "hoe");
 | 
					 | 
				
			||||||
        clientDetails.setAccessTokenValiditySeconds(3600);
 | 
					 | 
				
			||||||
        clientDetails.setRefreshTokenValiditySeconds(36000000);
 | 
					 | 
				
			||||||
        return clientDetails;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,74 +0,0 @@
 | 
				
			||||||
package com.recovery.auth.security.details.user;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.io.Serializable;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class JwtAuthenticationRequest implements Serializable {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private static final long serialVersionUID = -8445943548965154778L;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private String username;
 | 
					 | 
				
			||||||
    private String phone;
 | 
					 | 
				
			||||||
    private String password;
 | 
					 | 
				
			||||||
    private String verifyCode;
 | 
					 | 
				
			||||||
    private String loginMethod;
 | 
					 | 
				
			||||||
    private String visitorsType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public JwtAuthenticationRequest(String username,String phone,String password,String verifyCode,String loginMethod,String visitorsType) {
 | 
					 | 
				
			||||||
        this.username = username;
 | 
					 | 
				
			||||||
        this.phone = phone;
 | 
					 | 
				
			||||||
        this.password = password;
 | 
					 | 
				
			||||||
        this.verifyCode = verifyCode;
 | 
					 | 
				
			||||||
        this.loginMethod = loginMethod;
 | 
					 | 
				
			||||||
        this.visitorsType = visitorsType;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public JwtAuthenticationRequest() {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public String getPassword() {
 | 
					 | 
				
			||||||
        return password;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void setPassword(String password) {
 | 
					 | 
				
			||||||
        this.password = password;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public String getUsername() {
 | 
					 | 
				
			||||||
        return username;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void setUsername(String username) {
 | 
					 | 
				
			||||||
        this.username = username;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public String getUserPhone() {
 | 
					 | 
				
			||||||
        return phone;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void setUserPhone(String phone) {
 | 
					 | 
				
			||||||
        this.phone = phone;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public String getVerifyCode() {
 | 
					 | 
				
			||||||
        return verifyCode;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void setVerifyCode(String verifyCode) {
 | 
					 | 
				
			||||||
        this.verifyCode = verifyCode;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public String getLoginMethod() {
 | 
					 | 
				
			||||||
        return loginMethod;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void setLoginMethod(String loginMethod) {
 | 
					 | 
				
			||||||
        this.loginMethod = loginMethod;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    public String getVisitorsType() {
 | 
					 | 
				
			||||||
        return visitorsType;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void setVisitorsType(String visitorsType) {
 | 
					 | 
				
			||||||
        this.visitorsType = visitorsType;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,76 +0,0 @@
 | 
				
			||||||
package com.recovery.auth.security.details.user;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import lombok.AllArgsConstructor;
 | 
					 | 
				
			||||||
import lombok.Builder;
 | 
					 | 
				
			||||||
import lombok.Data;
 | 
					 | 
				
			||||||
import lombok.NoArgsConstructor;
 | 
					 | 
				
			||||||
import org.springframework.security.core.GrantedAuthority;
 | 
					 | 
				
			||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
 | 
					 | 
				
			||||||
import org.springframework.security.core.userdetails.UserDetails;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.Collection;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * @author: 
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
@Data
 | 
					 | 
				
			||||||
@Builder
 | 
					 | 
				
			||||||
@AllArgsConstructor
 | 
					 | 
				
			||||||
@NoArgsConstructor
 | 
					 | 
				
			||||||
public class SysUserDetails implements UserDetails {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 扩展字段
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private Long userId;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 默认字段
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private String username;
 | 
					 | 
				
			||||||
    private String password;
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 是否启用
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private Boolean enabled;
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * 角色
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private Collection<SimpleGrantedAuthority> authorities;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public Collection<? extends GrantedAuthority> getAuthorities() {
 | 
					 | 
				
			||||||
        return this.authorities;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public String getPassword() {
 | 
					 | 
				
			||||||
        return this.password;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public String getUsername() {
 | 
					 | 
				
			||||||
        return this.username;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public boolean isAccountNonExpired() {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public boolean isAccountNonLocked() {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public boolean isCredentialsNonExpired() {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public boolean isEnabled() {
 | 
					 | 
				
			||||||
        return this.enabled;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,79 +0,0 @@
 | 
				
			||||||
package com.recovery.auth.security.details.user;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.recovery.auth.feign.UserFeignClient;
 | 
					 | 
				
			||||||
import com.recovery.common.base.dto.UserAuthDTO;
 | 
					 | 
				
			||||||
import com.recovery.common.base.enums.PasswordEncoderTypeEnum;
 | 
					 | 
				
			||||||
import com.recovery.common.base.result.ApiResult;
 | 
					 | 
				
			||||||
import com.recovery.common.base.result.ResultCode;
 | 
					 | 
				
			||||||
import com.recovery.common.base.util.RedisUtil;
 | 
					 | 
				
			||||||
import lombok.RequiredArgsConstructor;
 | 
					 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					 | 
				
			||||||
import org.springframework.security.authentication.AccountExpiredException;
 | 
					 | 
				
			||||||
import org.springframework.security.authentication.DisabledException;
 | 
					 | 
				
			||||||
import org.springframework.security.authentication.LockedException;
 | 
					 | 
				
			||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
 | 
					 | 
				
			||||||
import org.springframework.security.core.userdetails.UserDetails;
 | 
					 | 
				
			||||||
import org.springframework.security.core.userdetails.UserDetailsService;
 | 
					 | 
				
			||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
 | 
					 | 
				
			||||||
import org.springframework.stereotype.Service;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javax.annotation.Resource;
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.Collection;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
import java.util.Objects;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * @author: 
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
@Service("sysUserDetailsService")
 | 
					 | 
				
			||||||
@Slf4j
 | 
					 | 
				
			||||||
@RequiredArgsConstructor
 | 
					 | 
				
			||||||
public class SysUserDetailsServiceImpl implements UserDetailsService {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Resource
 | 
					 | 
				
			||||||
    private UserFeignClient userFeignClient;
 | 
					 | 
				
			||||||
    @Resource
 | 
					 | 
				
			||||||
    RedisUtil redisUtil;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
 | 
					 | 
				
			||||||
        // 后面从管理端获取用户信息
 | 
					 | 
				
			||||||
        ApiResult<UserAuthDTO> result = userFeignClient.getUserByUsername(username);
 | 
					 | 
				
			||||||
        SysUserDetails userDetails = null;
 | 
					 | 
				
			||||||
        if (ApiResult.ok().getCode().equals(result.getCode())) {
 | 
					 | 
				
			||||||
            UserAuthDTO user = result.getData();
 | 
					 | 
				
			||||||
            if (null != user) {
 | 
					 | 
				
			||||||
                userDetails = SysUserDetails.builder()
 | 
					 | 
				
			||||||
                        .userId(user.getUserId())
 | 
					 | 
				
			||||||
                        .username(user.getUserName())
 | 
					 | 
				
			||||||
                        //角色
 | 
					 | 
				
			||||||
//                        .authorities(handleRoles(user.getRoles()))
 | 
					 | 
				
			||||||
                        .enabled(user.getStatus() == 1)
 | 
					 | 
				
			||||||
                        .password(PasswordEncoderTypeEnum.BCRYPT.getPrefix() + user.getPassword())
 | 
					 | 
				
			||||||
                        .build();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (Objects.isNull(userDetails)) {
 | 
					 | 
				
			||||||
            throw new UsernameNotFoundException(ResultCode.USER_NOT_EXIST.getMsg());
 | 
					 | 
				
			||||||
        } else if (!userDetails.isEnabled()) {
 | 
					 | 
				
			||||||
            throw new DisabledException("该账户已被禁用!");
 | 
					 | 
				
			||||||
        } else if (!userDetails.isAccountNonLocked()) {
 | 
					 | 
				
			||||||
            throw new LockedException("该账号已被锁定!");
 | 
					 | 
				
			||||||
        } else if (!userDetails.isAccountNonExpired()) {
 | 
					 | 
				
			||||||
            throw new AccountExpiredException("该账号已过期!");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return userDetails;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Collection<SimpleGrantedAuthority> handleRoles(List<String> roles) {
 | 
					 | 
				
			||||||
        Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
 | 
					 | 
				
			||||||
        for (String role : roles) {
 | 
					 | 
				
			||||||
            authorities.add(new SimpleGrantedAuthority(role));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return authorities;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,9 @@
 | 
				
			||||||
package com.recovery.auth.service.impl;
 | 
					package com.recovery.auth.service.impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.alibaba.fastjson.JSON;
 | 
					 | 
				
			||||||
import com.recovery.auth.exception.BusinessException;
 | 
					import com.recovery.auth.exception.BusinessException;
 | 
				
			||||||
import com.recovery.auth.feign.UserFeignClient;
 | 
					import com.recovery.auth.feign.UserFeignClient;
 | 
				
			||||||
import com.recovery.auth.security.details.user.JwtAuthenticationRequest;
 | 
					import com.recovery.auth.security.details.user.JwtAuthenticationRequest;
 | 
				
			||||||
import com.recovery.auth.security.details.user.SysUserDetails;
 | 
					 | 
				
			||||||
import com.recovery.auth.service.AuthService;
 | 
					import com.recovery.auth.service.AuthService;
 | 
				
			||||||
import com.recovery.common.base.dto.UserAuthDTO;
 | 
					import com.recovery.common.base.dto.UserAuthDTO;
 | 
				
			||||||
import com.recovery.common.base.dto.UserAuthorityDto;
 | 
					import com.recovery.common.base.dto.UserAuthorityDto;
 | 
				
			||||||
| 
						 | 
					@ -15,16 +13,11 @@ import com.recovery.common.base.util.EncryptUtil;
 | 
				
			||||||
import com.recovery.common.base.util.RedisUtil;
 | 
					import com.recovery.common.base.util.RedisUtil;
 | 
				
			||||||
import com.recovery.common.base.utils.JwtUtils;
 | 
					import com.recovery.common.base.utils.JwtUtils;
 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
import org.springframework.security.authentication.AccountExpiredException;
 | 
					 | 
				
			||||||
import org.springframework.security.authentication.DisabledException;
 | 
					 | 
				
			||||||
import org.springframework.security.authentication.LockedException;
 | 
					 | 
				
			||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
 | 
					 | 
				
			||||||
import org.springframework.stereotype.Service;
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Resource;
 | 
					import javax.annotation.Resource;
 | 
				
			||||||
import javax.servlet.http.HttpServletRequest;
 | 
					import javax.servlet.http.HttpServletRequest;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.Map;
 | 
					 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,6 +48,22 @@
 | 
				
			||||||
            <artifactId>spring-jdbc</artifactId>
 | 
					            <artifactId>spring-jdbc</artifactId>
 | 
				
			||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- httpClient依赖,缺少此依赖api网关转发请求时可能发生503错误 -->
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.apache.httpcomponents</groupId>
 | 
				
			||||||
 | 
					            <artifactId>httpclient</artifactId>
 | 
				
			||||||
 | 
					            <version>4.5.13</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.dev33</groupId>
 | 
				
			||||||
 | 
					            <artifactId>sa-token-reactor-spring-boot-starter</artifactId>
 | 
				
			||||||
 | 
					            <version>1.34.0</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- MySQL 连接驱动依赖 -->
 | 
					        <!-- MySQL 连接驱动依赖 -->
 | 
				
			||||||
        <dependency>
 | 
					        <dependency>
 | 
				
			||||||
            <groupId>mysql</groupId>
 | 
					            <groupId>mysql</groupId>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					package com.recovery.gateway.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.dev33.satoken.reactor.filter.SaReactorFilter;
 | 
				
			||||||
 | 
					import cn.dev33.satoken.router.SaRouter;
 | 
				
			||||||
 | 
					import cn.dev33.satoken.stp.StpUtil;
 | 
				
			||||||
 | 
					import cn.dev33.satoken.util.SaResult;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Bean;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * [Sa-Token 权限认证] 配置类
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Configuration
 | 
				
			||||||
 | 
					public class SaTokenConfigure {
 | 
				
			||||||
 | 
					    // 注册 Sa-Token全局过滤器
 | 
				
			||||||
 | 
					    @Bean
 | 
				
			||||||
 | 
					    public SaReactorFilter getSaReactorFilter() {
 | 
				
			||||||
 | 
					        return new SaReactorFilter()
 | 
				
			||||||
 | 
					                // 拦截地址
 | 
				
			||||||
 | 
					                .addInclude("/**")    /* 拦截全部path */
 | 
				
			||||||
 | 
					                // 开放地址
 | 
				
			||||||
 | 
					                .addExclude("/favicon.ico")
 | 
				
			||||||
 | 
					                // 鉴权方法:每次访问进入
 | 
				
			||||||
 | 
					                .setAuth(obj -> {
 | 
				
			||||||
 | 
					                    // 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
 | 
				
			||||||
 | 
					                    SaRouter.match("/**", "/auth/oauth/doLogin", r -> StpUtil.checkLogin());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // 权限认证 -- 不同模块, 校验不同权限
 | 
				
			||||||
 | 
					                    SaRouter.match("/api/test1", r -> StpUtil.checkPermission("api.test1"));
 | 
				
			||||||
 | 
					                    SaRouter.match("/api/test2", r -> StpUtil.checkPermission("api.test2"));
 | 
				
			||||||
 | 
					                    SaRouter.match("/api/test3", r -> StpUtil.checkRoleOr("admin", "super"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // 更多匹配 ...  */
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                // 异常处理方法:每次setAuth函数出现异常时进入
 | 
				
			||||||
 | 
					                .setError(e -> {
 | 
				
			||||||
 | 
					                    return SaResult.error(e.getMessage());
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,80 +1,80 @@
 | 
				
			||||||
package com.recovery.gateway.security;
 | 
					//package com.recovery.gateway.security;
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
import com.recovery.common.base.constant.SecurityConstants;
 | 
					//import com.recovery.common.base.constant.SecurityConstants;
 | 
				
			||||||
import com.recovery.common.base.result.ResultCode;
 | 
					//import com.recovery.common.base.result.ResultCode;
 | 
				
			||||||
import com.recovery.gateway.util.ResponseUtils;
 | 
					//import com.recovery.gateway.util.ResponseUtils;
 | 
				
			||||||
import lombok.AllArgsConstructor;
 | 
					//import lombok.AllArgsConstructor;
 | 
				
			||||||
import org.springframework.context.annotation.Bean;
 | 
					//import org.springframework.context.annotation.Bean;
 | 
				
			||||||
import org.springframework.context.annotation.Configuration;
 | 
					//import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
import org.springframework.core.convert.converter.Converter;
 | 
					//import org.springframework.core.convert.converter.Converter;
 | 
				
			||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
 | 
					//import org.springframework.security.authentication.AbstractAuthenticationToken;
 | 
				
			||||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
 | 
					//import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
 | 
				
			||||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
 | 
					//import org.springframework.security.config.web.server.ServerHttpSecurity;
 | 
				
			||||||
import org.springframework.security.oauth2.jwt.Jwt;
 | 
					//import org.springframework.security.oauth2.jwt.Jwt;
 | 
				
			||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
 | 
					//import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
 | 
				
			||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
 | 
					//import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
 | 
				
			||||||
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
 | 
					//import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
 | 
				
			||||||
import org.springframework.security.web.server.SecurityWebFilterChain;
 | 
					//import org.springframework.security.web.server.SecurityWebFilterChain;
 | 
				
			||||||
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
 | 
					//import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
 | 
				
			||||||
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
 | 
					//import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
 | 
				
			||||||
import reactor.core.publisher.Mono;
 | 
					//import reactor.core.publisher.Mono;
 | 
				
			||||||
/**
 | 
					///**
 | 
				
			||||||
 * @author: 
 | 
					// * @author:
 | 
				
			||||||
 */
 | 
					// */
 | 
				
			||||||
@AllArgsConstructor
 | 
					//@AllArgsConstructor
 | 
				
			||||||
@Configuration
 | 
					//@Configuration
 | 
				
			||||||
@EnableWebFluxSecurity
 | 
					//@EnableWebFluxSecurity
 | 
				
			||||||
public class ResourceServerConfig {
 | 
					//public class ResourceServerConfig {
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
    private final ResourceServerManager resourceServerManager;
 | 
					//    private final ResourceServerManager resourceServerManager;
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
    @Bean
 | 
					//    @Bean
 | 
				
			||||||
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
 | 
					//    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
 | 
				
			||||||
        http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter());
 | 
					//        http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter());
 | 
				
			||||||
        http.oauth2ResourceServer().authenticationEntryPoint(authenticationEntryPoint());
 | 
					//        http.oauth2ResourceServer().authenticationEntryPoint(authenticationEntryPoint());
 | 
				
			||||||
        http.authorizeExchange()
 | 
					//        http.authorizeExchange()
 | 
				
			||||||
                .anyExchange().access(resourceServerManager)
 | 
					//                .anyExchange().access(resourceServerManager)
 | 
				
			||||||
                .and()
 | 
					//                .and()
 | 
				
			||||||
                .exceptionHandling()
 | 
					//                .exceptionHandling()
 | 
				
			||||||
                .accessDeniedHandler(accessDeniedHandler()) // 处理未授权
 | 
					//                .accessDeniedHandler(accessDeniedHandler()) // 处理未授权
 | 
				
			||||||
                .authenticationEntryPoint(authenticationEntryPoint()) //处理未认证
 | 
					//                .authenticationEntryPoint(authenticationEntryPoint()) //处理未认证
 | 
				
			||||||
                .and().csrf().disable();
 | 
					//                .and().csrf().disable();
 | 
				
			||||||
        return http.build();
 | 
					//        return http.build();
 | 
				
			||||||
    }
 | 
					//    }
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
    /**
 | 
					//    /**
 | 
				
			||||||
     * 自定义未授权响应
 | 
					//     * 自定义未授权响应
 | 
				
			||||||
     */
 | 
					//     */
 | 
				
			||||||
    @Bean
 | 
					//    @Bean
 | 
				
			||||||
    ServerAccessDeniedHandler accessDeniedHandler() {
 | 
					//    ServerAccessDeniedHandler accessDeniedHandler() {
 | 
				
			||||||
        return (exchange, denied) -> {
 | 
					//        return (exchange, denied) -> {
 | 
				
			||||||
            Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
 | 
					//            Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
 | 
				
			||||||
                    .flatMap(response -> ResponseUtils.writeErrorInfo(response, ResultCode.ACCESS_UNAUTHORIZED));
 | 
					//                    .flatMap(response -> ResponseUtils.writeErrorInfo(response, ResultCode.ACCESS_UNAUTHORIZED));
 | 
				
			||||||
            return mono;
 | 
					//            return mono;
 | 
				
			||||||
        };
 | 
					//        };
 | 
				
			||||||
    }
 | 
					//    }
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
    /**
 | 
					//    /**
 | 
				
			||||||
     * token无效或者已过期自定义响应
 | 
					//     * token无效或者已过期自定义响应
 | 
				
			||||||
     */
 | 
					//     */
 | 
				
			||||||
    @Bean
 | 
					//    @Bean
 | 
				
			||||||
    ServerAuthenticationEntryPoint authenticationEntryPoint() {
 | 
					//    ServerAuthenticationEntryPoint authenticationEntryPoint() {
 | 
				
			||||||
        return (exchange, e) -> {
 | 
					//        return (exchange, e) -> {
 | 
				
			||||||
            Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
 | 
					//            Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
 | 
				
			||||||
                    .flatMap(response -> ResponseUtils.writeErrorInfo(response, ResultCode.TOKEN_INVALID_OR_EXPIRED));
 | 
					//                    .flatMap(response -> ResponseUtils.writeErrorInfo(response, ResultCode.TOKEN_INVALID_OR_EXPIRED));
 | 
				
			||||||
            return mono;
 | 
					//            return mono;
 | 
				
			||||||
        };
 | 
					//        };
 | 
				
			||||||
    }
 | 
					//    }
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
    @Bean
 | 
					//    @Bean
 | 
				
			||||||
    public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
 | 
					//    public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
 | 
				
			||||||
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
 | 
					//        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
 | 
				
			||||||
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix(SecurityConstants.AUTHORITY_PREFIX);
 | 
					//        jwtGrantedAuthoritiesConverter.setAuthorityPrefix(SecurityConstants.AUTHORITY_PREFIX);
 | 
				
			||||||
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(SecurityConstants.JWT_AUTHORITIES_KEY);
 | 
					//        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(SecurityConstants.JWT_AUTHORITIES_KEY);
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
 | 
					//        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
 | 
				
			||||||
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
 | 
					//        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
 | 
				
			||||||
        return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
 | 
					//        return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
 | 
				
			||||||
    }
 | 
					//    }
 | 
				
			||||||
}
 | 
					//}
 | 
				
			||||||
| 
						 | 
					@ -1,122 +1,79 @@
 | 
				
			||||||
package com.recovery.gateway.security;
 | 
					//package com.recovery.gateway.security;
 | 
				
			||||||
 | 
					 | 
				
			||||||
import cn.hutool.core.collection.CollectionUtil;
 | 
					 | 
				
			||||||
import cn.hutool.core.convert.Convert;
 | 
					 | 
				
			||||||
import cn.hutool.core.util.StrUtil;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.recovery.common.base.constant.GlobalConstants;
 | 
					 | 
				
			||||||
import com.recovery.common.base.constant.SecurityConstants;
 | 
					 | 
				
			||||||
import com.recovery.gateway.util.UrlPatternUtils;
 | 
					 | 
				
			||||||
import lombok.RequiredArgsConstructor;
 | 
					 | 
				
			||||||
import lombok.Setter;
 | 
					 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					 | 
				
			||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
 | 
					 | 
				
			||||||
import org.springframework.data.redis.core.RedisTemplate;
 | 
					 | 
				
			||||||
import org.springframework.http.HttpMethod;
 | 
					 | 
				
			||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
 | 
					 | 
				
			||||||
import org.springframework.security.authorization.AuthorizationDecision;
 | 
					 | 
				
			||||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
 | 
					 | 
				
			||||||
import org.springframework.security.core.Authentication;
 | 
					 | 
				
			||||||
import org.springframework.security.core.GrantedAuthority;
 | 
					 | 
				
			||||||
import org.springframework.security.web.server.authorization.AuthorizationContext;
 | 
					 | 
				
			||||||
import org.springframework.stereotype.Component;
 | 
					 | 
				
			||||||
import org.springframework.util.AntPathMatcher;
 | 
					 | 
				
			||||||
import org.springframework.util.PathMatcher;
 | 
					 | 
				
			||||||
import reactor.core.publisher.Mono;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
import java.util.Map;
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Created with IntelliJ IDEA.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author: AI码师 关注公众号"AI码师"获取完整源码
 | 
					 | 
				
			||||||
 * @date: 2021/11/24
 | 
					 | 
				
			||||||
 * @description:
 | 
					 | 
				
			||||||
 * @modifiedBy:
 | 
					 | 
				
			||||||
 * @version: 1.0
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
@Component
 | 
					 | 
				
			||||||
@RequiredArgsConstructor
 | 
					 | 
				
			||||||
@Slf4j
 | 
					 | 
				
			||||||
@ConfigurationProperties(prefix = "security")
 | 
					 | 
				
			||||||
public class ResourceServerManager implements ReactiveAuthorizationManager<AuthorizationContext> {
 | 
					 | 
				
			||||||
    private final RedisTemplate redisTemplate;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Setter
 | 
					 | 
				
			||||||
    private List<String> ignoreUrls;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
 | 
					 | 
				
			||||||
        ServerHttpRequest request = authorizationContext.getExchange().getRequest();
 | 
					 | 
				
			||||||
        if (request.getMethod() == HttpMethod.OPTIONS) { // 预检请求放行
 | 
					 | 
				
			||||||
            return Mono.just(new AuthorizationDecision(true));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        PathMatcher pathMatcher = new AntPathMatcher();
 | 
					 | 
				
			||||||
        String method = request.getMethodValue();
 | 
					 | 
				
			||||||
        String path = request.getURI().getPath();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 跳过token校验,放在这里去做是为了能够动态刷新
 | 
					 | 
				
			||||||
//        if (skipValid(path)) {
 | 
					 | 
				
			||||||
            return Mono.just(new AuthorizationDecision(true));
 | 
					 | 
				
			||||||
//        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//        // 如果token为空 或者token不合法 则进行拦截
 | 
					 | 
				
			||||||
//        String restfulPath = method + ":" + path; // RESTFul接口权限设计 @link https://www.cnblogs.com/haoxianrui/p/14961707.html
 | 
					 | 
				
			||||||
//        String token = request.getHeaders().getFirst(SecurityConstants.AUTHORIZATION_KEY);
 | 
					 | 
				
			||||||
//        if (StrUtil.isBlank(token) || !StrUtil.startWithIgnoreCase(token, SecurityConstants.JWT_PREFIX)) {
 | 
					 | 
				
			||||||
//            return Mono.just(new AuthorizationDecision(false));
 | 
					 | 
				
			||||||
//        }
 | 
					 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//        // 从redis中获取资源权限
 | 
					//import cn.hutool.core.collection.CollectionUtil;
 | 
				
			||||||
//        Map<String, Object> urlPermRolesRules = redisTemplate.opsForHash().entries(GlobalConstants.URL_PERM_ROLES_KEY);
 | 
					//import cn.hutool.core.convert.Convert;
 | 
				
			||||||
//        List<String> authorizedRoles = new ArrayList<>(); // 拥有访问权限的角色
 | 
					//import cn.hutool.core.util.StrUtil;
 | 
				
			||||||
//        boolean requireCheck = false; // 是否需要鉴权,默认未设置拦截规则不需鉴权
 | 
					 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//        // 获取当前资源 所需要的角色
 | 
					//import com.recovery.common.base.constant.GlobalConstants;
 | 
				
			||||||
//        for (Map.Entry<String, Object> permRoles : urlPermRolesRules.entrySet()) {
 | 
					//import com.recovery.common.base.constant.SecurityConstants;
 | 
				
			||||||
//            String perm = permRoles.getKey();
 | 
					//import com.recovery.gateway.util.UrlPatternUtils;
 | 
				
			||||||
//            if (pathMatcher.match(perm, restfulPath)) {
 | 
					//import lombok.RequiredArgsConstructor;
 | 
				
			||||||
//                List<String> roles = Convert.toList(String.class, permRoles.getValue());
 | 
					//import lombok.Setter;
 | 
				
			||||||
//                authorizedRoles.addAll(Convert.toList(String.class, roles));
 | 
					//import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
//                if (requireCheck == false) {
 | 
					//import org.springframework.boot.context.properties.ConfigurationProperties;
 | 
				
			||||||
//                    requireCheck = true;
 | 
					//import org.springframework.data.redis.core.RedisTemplate;
 | 
				
			||||||
//                }
 | 
					//import org.springframework.http.HttpMethod;
 | 
				
			||||||
//            }
 | 
					//import org.springframework.http.server.reactive.ServerHttpRequest;
 | 
				
			||||||
//        }
 | 
					//import org.springframework.security.authorization.AuthorizationDecision;
 | 
				
			||||||
 | 
					//import org.springframework.security.authorization.ReactiveAuthorizationManager;
 | 
				
			||||||
 | 
					//import org.springframework.security.core.Authentication;
 | 
				
			||||||
 | 
					//import org.springframework.security.core.GrantedAuthority;
 | 
				
			||||||
 | 
					//import org.springframework.security.web.server.authorization.AuthorizationContext;
 | 
				
			||||||
 | 
					//import org.springframework.stereotype.Component;
 | 
				
			||||||
 | 
					//import org.springframework.util.AntPathMatcher;
 | 
				
			||||||
 | 
					//import org.springframework.util.PathMatcher;
 | 
				
			||||||
 | 
					//import reactor.core.publisher.Mono;
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//        // 如果资源不需要权限 则直接返回授权成功
 | 
					//import java.util.ArrayList;
 | 
				
			||||||
//        if (!requireCheck) {
 | 
					//import java.util.List;
 | 
				
			||||||
 | 
					//import java.util.Map;
 | 
				
			||||||
 | 
					///**
 | 
				
			||||||
 | 
					// * Created with IntelliJ IDEA.
 | 
				
			||||||
 | 
					// *
 | 
				
			||||||
 | 
					// * @author:
 | 
				
			||||||
 | 
					// * @date: 2021/11/24
 | 
				
			||||||
 | 
					// * @description:
 | 
				
			||||||
 | 
					// * @modifiedBy:
 | 
				
			||||||
 | 
					// * @version: 1.0
 | 
				
			||||||
 | 
					// */
 | 
				
			||||||
 | 
					//@Component
 | 
				
			||||||
 | 
					//@RequiredArgsConstructor
 | 
				
			||||||
 | 
					//@Slf4j
 | 
				
			||||||
 | 
					//@ConfigurationProperties(prefix = "security")
 | 
				
			||||||
 | 
					//public class ResourceServerManager implements ReactiveAuthorizationManager<AuthorizationContext> {
 | 
				
			||||||
 | 
					//    private final RedisTemplate redisTemplate;
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//    @Setter
 | 
				
			||||||
 | 
					//    private List<String> ignoreUrls;
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//    @Override
 | 
				
			||||||
 | 
					//    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
 | 
				
			||||||
 | 
					//        ServerHttpRequest request = authorizationContext.getExchange().getRequest();
 | 
				
			||||||
 | 
					//        if (request.getMethod() == HttpMethod.OPTIONS) { // 预检请求放行
 | 
				
			||||||
//            return Mono.just(new AuthorizationDecision(true));
 | 
					//            return Mono.just(new AuthorizationDecision(true));
 | 
				
			||||||
//        }
 | 
					//        }
 | 
				
			||||||
 | 
					//        PathMatcher pathMatcher = new AntPathMatcher();
 | 
				
			||||||
 | 
					//        String method = request.getMethodValue();
 | 
				
			||||||
 | 
					//        String path = request.getURI().getPath();
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//        // 判断JWT中携带的用户角色是否有权限访问
 | 
					//        // 跳过token校验,放在这里去做是为了能够动态刷新
 | 
				
			||||||
//        Mono<AuthorizationDecision> authorizationDecisionMono = mono
 | 
					////        if (skipValid(path)) {
 | 
				
			||||||
//                .filter(Authentication::isAuthenticated)
 | 
					//            return Mono.just(new AuthorizationDecision(true));
 | 
				
			||||||
//                .flatMapIterable(Authentication::getAuthorities)
 | 
					////        }
 | 
				
			||||||
//                .map(GrantedAuthority::getAuthority)
 | 
					//    }
 | 
				
			||||||
//                .any(authority -> {
 | 
					//
 | 
				
			||||||
//                    String roleCode = authority.substring(SecurityConstants.AUTHORITY_PREFIX.length()); // 用户的角色
 | 
					//    /**
 | 
				
			||||||
//                    boolean hasAuthorized = CollectionUtil.isNotEmpty(authorizedRoles) && authorizedRoles.contains(roleCode);
 | 
					//     * 跳过校验
 | 
				
			||||||
//                    return hasAuthorized;
 | 
					//     *
 | 
				
			||||||
//                })
 | 
					//     * @param path
 | 
				
			||||||
//                .map(AuthorizationDecision::new)
 | 
					//     * @return
 | 
				
			||||||
//                .defaultIfEmpty(new AuthorizationDecision(false));
 | 
					//     */
 | 
				
			||||||
//        return authorizationDecisionMono;
 | 
					//    private boolean skipValid(String path) {
 | 
				
			||||||
    }
 | 
					//        for (String skipPath : ignoreUrls) {
 | 
				
			||||||
 | 
					//            if (UrlPatternUtils.match(skipPath, path)) {
 | 
				
			||||||
    /**
 | 
					//                return true;
 | 
				
			||||||
     * 跳过校验
 | 
					//            }
 | 
				
			||||||
     *
 | 
					//        }
 | 
				
			||||||
     * @param path
 | 
					//        return false;
 | 
				
			||||||
     * @return
 | 
					//    }
 | 
				
			||||||
     */
 | 
					//}
 | 
				
			||||||
    private boolean skipValid(String path) {
 | 
					 | 
				
			||||||
        for (String skipPath : ignoreUrls) {
 | 
					 | 
				
			||||||
            if (UrlPatternUtils.match(skipPath, path)) {
 | 
					 | 
				
			||||||
                return true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,62 +1,69 @@
 | 
				
			||||||
package com.recovery.gateway.security;
 | 
					//package com.recovery.gateway.security;
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
import cn.hutool.core.util.StrUtil;
 | 
					//import cn.dev33.satoken.same.SaSameUtil;
 | 
				
			||||||
 | 
					//import cn.hutool.core.util.StrUtil;
 | 
				
			||||||
import com.nimbusds.jose.JWSObject;
 | 
					//
 | 
				
			||||||
import com.recovery.common.base.constant.SecurityConstants;
 | 
					//import com.nimbusds.jose.JWSObject;
 | 
				
			||||||
import lombok.RequiredArgsConstructor;
 | 
					//import com.recovery.common.base.constant.SecurityConstants;
 | 
				
			||||||
import lombok.SneakyThrows;
 | 
					//import lombok.RequiredArgsConstructor;
 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					//import lombok.SneakyThrows;
 | 
				
			||||||
import org.apache.logging.log4j.util.Strings;
 | 
					//import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
 | 
					//import org.apache.logging.log4j.util.Strings;
 | 
				
			||||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
 | 
					//import org.springframework.cloud.gateway.filter.GatewayFilterChain;
 | 
				
			||||||
import org.springframework.core.Ordered;
 | 
					//import org.springframework.cloud.gateway.filter.GlobalFilter;
 | 
				
			||||||
import org.springframework.data.redis.core.RedisTemplate;
 | 
					//import org.springframework.core.Ordered;
 | 
				
			||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
 | 
					//import org.springframework.data.redis.core.RedisTemplate;
 | 
				
			||||||
import org.springframework.http.server.reactive.ServerHttpResponse;
 | 
					//import org.springframework.http.server.reactive.ServerHttpRequest;
 | 
				
			||||||
import org.springframework.stereotype.Component;
 | 
					//import org.springframework.http.server.reactive.ServerHttpResponse;
 | 
				
			||||||
import org.springframework.web.server.ServerWebExchange;
 | 
					//import org.springframework.stereotype.Component;
 | 
				
			||||||
import reactor.core.publisher.Mono;
 | 
					//import org.springframework.web.server.ServerWebExchange;
 | 
				
			||||||
 | 
					//import reactor.core.publisher.Mono;
 | 
				
			||||||
import java.net.URLEncoder;
 | 
					//
 | 
				
			||||||
/**
 | 
					//import java.net.URLEncoder;
 | 
				
			||||||
 * Created with IntelliJ IDEA.
 | 
					///**
 | 
				
			||||||
 *
 | 
					// * Created with IntelliJ IDEA.
 | 
				
			||||||
 * @author: AI码师 关注公众号"AI码师"获取完整源码
 | 
					// *
 | 
				
			||||||
 * @date: 2021/11/24
 | 
					// * @author: AI码师 关注公众号"AI码师"获取完整源码
 | 
				
			||||||
 * @description:
 | 
					// * @date: 2021/11/24
 | 
				
			||||||
 * @modifiedBy:
 | 
					// * @description:
 | 
				
			||||||
 * @version: 1.0
 | 
					// * @modifiedBy:
 | 
				
			||||||
 */
 | 
					// * @version: 1.0
 | 
				
			||||||
@Component
 | 
					// */
 | 
				
			||||||
@Slf4j
 | 
					//@Component
 | 
				
			||||||
@RequiredArgsConstructor
 | 
					//@Slf4j
 | 
				
			||||||
public class SecurityGlobalFilter implements GlobalFilter, Ordered {
 | 
					//@RequiredArgsConstructor
 | 
				
			||||||
 | 
					//public class SecurityGlobalFilter implements GlobalFilter, Ordered {
 | 
				
			||||||
    @SneakyThrows
 | 
					//
 | 
				
			||||||
    @Override
 | 
					//    @SneakyThrows
 | 
				
			||||||
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
 | 
					//    @Override
 | 
				
			||||||
 | 
					//    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
 | 
				
			||||||
        ServerHttpRequest request = exchange.getRequest();
 | 
					//
 | 
				
			||||||
        log.info("接受到请求地址:"+request.getURI());
 | 
					//        ServerHttpRequest request = exchange.getRequest();
 | 
				
			||||||
        ServerHttpResponse response = exchange.getResponse();
 | 
					//        log.info("接受到请求地址:"+request.getURI());
 | 
				
			||||||
        // 不是正确的的JWT不做解析处理
 | 
					//        ServerHttpResponse response = exchange.getResponse();
 | 
				
			||||||
        String token = request.getHeaders().getFirst(SecurityConstants.AUTHORIZATION_KEY);
 | 
					//        // 不是正确的的JWT不做解析处理
 | 
				
			||||||
        if (StrUtil.isBlank(token) || !StrUtil.startWithIgnoreCase(token, SecurityConstants.JWT_PREFIX)) {
 | 
					//        String token = request.getHeaders().getFirst(SecurityConstants.AUTHORIZATION_KEY);
 | 
				
			||||||
            return chain.filter(exchange);
 | 
					//        if (StrUtil.isBlank(token) || !StrUtil.startWithIgnoreCase(token, SecurityConstants.JWT_PREFIX)) {
 | 
				
			||||||
        }
 | 
					//            return chain.filter(exchange);
 | 
				
			||||||
        // 解析JWT获取jti,以jti为key判断redis的黑名单列表是否存在,存在则拦截访问
 | 
					//        }
 | 
				
			||||||
        token = StrUtil.replaceIgnoreCase(token, SecurityConstants.JWT_PREFIX, Strings.EMPTY);
 | 
					//        // 为请求追加 Same-Token 参数
 | 
				
			||||||
        String payload = StrUtil.toString(JWSObject.parse(token).getPayload());
 | 
					//        request.mutate()
 | 
				
			||||||
        request = exchange.getRequest().mutate()
 | 
					//                // 为请求追加 Same-Token 参数
 | 
				
			||||||
                .header(SecurityConstants.JWT_PAYLOAD_KEY, URLEncoder.encode(payload, "UTF-8"))
 | 
					//                .header(SaSameUtil.SAME_TOKEN, SaSameUtil.getToken())
 | 
				
			||||||
                .build();
 | 
					//                .build();
 | 
				
			||||||
        exchange = exchange.mutate().request(request).build();
 | 
					//        //结束
 | 
				
			||||||
        return chain.filter(exchange);
 | 
					//        // 解析JWT获取jti,以jti为key判断redis的黑名单列表是否存在,存在则拦截访问
 | 
				
			||||||
    }
 | 
					//        token = StrUtil.replaceIgnoreCase(token, SecurityConstants.JWT_PREFIX, Strings.EMPTY);
 | 
				
			||||||
 | 
					//        String payload = StrUtil.toString(JWSObject.parse(token).getPayload());
 | 
				
			||||||
    @Override
 | 
					//        request = exchange.getRequest().mutate()
 | 
				
			||||||
    public int getOrder() {
 | 
					//                .header(SecurityConstants.JWT_PAYLOAD_KEY, URLEncoder.encode(payload, "UTF-8"))
 | 
				
			||||||
        return 0;
 | 
					//                .build();
 | 
				
			||||||
    }
 | 
					//        exchange = exchange.mutate().request(request).build();
 | 
				
			||||||
}
 | 
					//        return chain.filter(exchange);
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//    @Override
 | 
				
			||||||
 | 
					//    public int getOrder() {
 | 
				
			||||||
 | 
					//        return 0;
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
							
								
								
									
										10
									
								
								pom.xml
								
								
								
								
							
							
						
						
									
										10
									
								
								pom.xml
								
								
								
								
							| 
						 | 
					@ -46,6 +46,16 @@
 | 
				
			||||||
            <artifactId>hutool-all</artifactId>
 | 
					            <artifactId>hutool-all</artifactId>
 | 
				
			||||||
            <version>${hutool-version}</version>
 | 
					            <version>${hutool-version}</version>
 | 
				
			||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>cn.dev33</groupId>
 | 
				
			||||||
 | 
					            <artifactId>sa-token-redis-jackson</artifactId>
 | 
				
			||||||
 | 
					            <version>1.37.0</version>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.apache.commons</groupId>
 | 
				
			||||||
 | 
					            <artifactId>commons-pool2</artifactId>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
    </dependencies>
 | 
					    </dependencies>
 | 
				
			||||||
    <!--    end  -->
 | 
					    <!--    end  -->
 | 
				
			||||||
    <dependencyManagement>
 | 
					    <dependencyManagement>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue