diff --git a/hoe-admin/admin-boot/pom.xml b/hoe-admin/admin-boot/pom.xml index d28b45c..7993851 100644 --- a/hoe-admin/admin-boot/pom.xml +++ b/hoe-admin/admin-boot/pom.xml @@ -53,6 +53,21 @@ spring-cloud-starter-alibaba-nacos-config + + + cn.dev33 + sa-token-spring-boot-starter + 1.37.0 + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.nimbusds diff --git a/hoe-admin/admin-boot/src/main/java/com/recovery/admin/boot/config/SaTokenConfigure.java b/hoe-admin/admin-boot/src/main/java/com/recovery/admin/boot/config/SaTokenConfigure.java new file mode 100644 index 0000000..54853a3 --- /dev/null +++ b/hoe-admin/admin-boot/src/main/java/com/recovery/admin/boot/config/SaTokenConfigure.java @@ -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()); + }) + ; + } +} \ No newline at end of file diff --git a/hoe-auth/pom.xml b/hoe-auth/pom.xml index 25fd989..3746785 100644 --- a/hoe-auth/pom.xml +++ b/hoe-auth/pom.xml @@ -35,6 +35,15 @@ spring-cloud-starter-alibaba-nacos-discovery + + + + cn.dev33 + sa-token-spring-boot-starter + 1.37.0 + + + org.springframework.cloud spring-cloud-starter-loadbalancer @@ -46,25 +55,13 @@ spring-cloud-starter-alibaba-nacos-config - - org.springframework.security - spring-security-oauth2-jose - + com.recovery common-web ${hoe-version} - - - org.springframework.security.oauth.boot - spring-security-oauth2-autoconfigure - - - org.springframework.security - spring-security-oauth2-jose - diff --git a/hoe-auth/src/main/java/com/recovery/auth/comm/exception/AuthExceptionHandler.java b/hoe-auth/src/main/java/com/recovery/auth/comm/exception/AuthExceptionHandler.java deleted file mode 100644 index 4c0ba1d..0000000 --- a/hoe-auth/src/main/java/com/recovery/auth/comm/exception/AuthExceptionHandler.java +++ /dev/null @@ -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()); - } - - -} diff --git a/hoe-auth/src/main/java/com/recovery/auth/comm/utils/CommonUtils.java b/hoe-auth/src/main/java/com/recovery/auth/comm/utils/CommonUtils.java deleted file mode 100644 index 528af4e..0000000 --- a/hoe-auth/src/main/java/com/recovery/auth/comm/utils/CommonUtils.java +++ /dev/null @@ -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; - } -} diff --git a/hoe-auth/src/main/java/com/recovery/auth/config/AuthorizationServerConfig.java b/hoe-auth/src/main/java/com/recovery/auth/config/AuthorizationServerConfig.java deleted file mode 100644 index 520d47c..0000000 --- a/hoe-auth/src/main/java/com/recovery/auth/config/AuthorizationServerConfig.java +++ /dev/null @@ -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 tokenEnhancers = new ArrayList<>(); - tokenEnhancers.add(tokenEnhancer()); - tokenEnhancers.add(jwtAccessTokenConverter()); - tokenEnhancerChain.setTokenEnhancers(tokenEnhancers); - - // 获取原有默认授权模式(授权码模式、密码模式、客户端模式、简化模式)的授权者 - List 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 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 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; - } -} \ No newline at end of file diff --git a/hoe-auth/src/main/java/com/recovery/auth/config/SaTokenConfigure.java b/hoe-auth/src/main/java/com/recovery/auth/config/SaTokenConfigure.java new file mode 100644 index 0000000..68849d3 --- /dev/null +++ b/hoe-auth/src/main/java/com/recovery/auth/config/SaTokenConfigure.java @@ -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()); + }) + ; + } +} \ No newline at end of file diff --git a/hoe-auth/src/main/java/com/recovery/auth/config/WebSecurityConfig.java b/hoe-auth/src/main/java/com/recovery/auth/config/WebSecurityConfig.java deleted file mode 100644 index b77aac9..0000000 --- a/hoe-auth/src/main/java/com/recovery/auth/config/WebSecurityConfig.java +++ /dev/null @@ -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(); - } -} \ No newline at end of file diff --git a/hoe-auth/src/main/java/com/recovery/auth/controller/AuthController.java b/hoe-auth/src/main/java/com/recovery/auth/controller/AuthController.java index c99d74f..fab7eba 100644 --- a/hoe-auth/src/main/java/com/recovery/auth/controller/AuthController.java +++ b/hoe-auth/src/main/java/com/recovery/auth/controller/AuthController.java @@ -1,25 +1,25 @@ package com.recovery.auth.controller; -import com.nimbusds.jose.jwk.JWKSet; -import com.nimbusds.jose.jwk.RSAKey; +import cn.dev33.satoken.stp.SaTokenInfo; +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.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.ResultCode; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint; -import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; 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.Map; /** * @author: @@ -32,6 +32,8 @@ public class AuthController { @Resource AuthService authService; + @Resource + UserFeignClient userFeignClient; @PostMapping("/token") public ApiResult postAccessToken(@RequestBody JwtAuthenticationRequest authenticationRequest, HttpServletRequest request){ @@ -46,6 +48,32 @@ public class AuthController { 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 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") // public Map getPublicKey() { // //单例模式 diff --git a/hoe-auth/src/main/java/com/recovery/auth/security/details/client/ClientDetailsServiceImpl.java b/hoe-auth/src/main/java/com/recovery/auth/security/details/client/ClientDetailsServiceImpl.java deleted file mode 100644 index 9d3bec7..0000000 --- a/hoe-auth/src/main/java/com/recovery/auth/security/details/client/ClientDetailsServiceImpl.java +++ /dev/null @@ -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; - } -} diff --git a/hoe-auth/src/main/java/com/recovery/auth/security/details/user/JwtAuthenticationRequest.java b/hoe-auth/src/main/java/com/recovery/auth/security/details/user/JwtAuthenticationRequest.java deleted file mode 100644 index 342f09e..0000000 --- a/hoe-auth/src/main/java/com/recovery/auth/security/details/user/JwtAuthenticationRequest.java +++ /dev/null @@ -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; - } -} diff --git a/hoe-auth/src/main/java/com/recovery/auth/security/details/user/SysUserDetails.java b/hoe-auth/src/main/java/com/recovery/auth/security/details/user/SysUserDetails.java deleted file mode 100644 index 89b04c3..0000000 --- a/hoe-auth/src/main/java/com/recovery/auth/security/details/user/SysUserDetails.java +++ /dev/null @@ -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 authorities; - - - @Override - public Collection 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; - } -} diff --git a/hoe-auth/src/main/java/com/recovery/auth/security/details/user/SysUserDetailsServiceImpl.java b/hoe-auth/src/main/java/com/recovery/auth/security/details/user/SysUserDetailsServiceImpl.java deleted file mode 100644 index 626cba7..0000000 --- a/hoe-auth/src/main/java/com/recovery/auth/security/details/user/SysUserDetailsServiceImpl.java +++ /dev/null @@ -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 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 handleRoles(List roles) { - Collection authorities = new ArrayList<>(); - for (String role : roles) { - authorities.add(new SimpleGrantedAuthority(role)); - } - return authorities; - } - - -} diff --git a/hoe-auth/src/main/java/com/recovery/auth/service/impl/AuthServiceImpl.java b/hoe-auth/src/main/java/com/recovery/auth/service/impl/AuthServiceImpl.java index e330dbd..2752009 100644 --- a/hoe-auth/src/main/java/com/recovery/auth/service/impl/AuthServiceImpl.java +++ b/hoe-auth/src/main/java/com/recovery/auth/service/impl/AuthServiceImpl.java @@ -1,11 +1,9 @@ package com.recovery.auth.service.impl; -import com.alibaba.fastjson.JSON; 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.SysUserDetails; import com.recovery.auth.service.AuthService; import com.recovery.common.base.dto.UserAuthDTO; 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.utils.JwtUtils; 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 javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; -import java.util.Map; import java.util.Objects; /** diff --git a/hoe-gateway/pom.xml b/hoe-gateway/pom.xml index 33e695d..4af5e16 100644 --- a/hoe-gateway/pom.xml +++ b/hoe-gateway/pom.xml @@ -48,6 +48,22 @@ spring-jdbc + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + + + + cn.dev33 + sa-token-reactor-spring-boot-starter + 1.34.0 + + + mysql diff --git a/hoe-gateway/src/main/java/com/recovery/gateway/config/SaTokenConfigure.java b/hoe-gateway/src/main/java/com/recovery/gateway/config/SaTokenConfigure.java new file mode 100644 index 0000000..9c949f7 --- /dev/null +++ b/hoe-gateway/src/main/java/com/recovery/gateway/config/SaTokenConfigure.java @@ -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()); + }) + ; + } +} diff --git a/hoe-gateway/src/main/java/com/recovery/gateway/security/ResourceServerConfig.java b/hoe-gateway/src/main/java/com/recovery/gateway/security/ResourceServerConfig.java index 4a869a3..e2af47c 100644 --- a/hoe-gateway/src/main/java/com/recovery/gateway/security/ResourceServerConfig.java +++ b/hoe-gateway/src/main/java/com/recovery/gateway/security/ResourceServerConfig.java @@ -1,80 +1,80 @@ -package com.recovery.gateway.security; - - -import com.recovery.common.base.constant.SecurityConstants; -import com.recovery.common.base.result.ResultCode; -import com.recovery.gateway.util.ResponseUtils; -import lombok.AllArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.convert.converter.Converter; -import org.springframework.security.authentication.AbstractAuthenticationToken; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.oauth2.jwt.Jwt; -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.ReactiveJwtAuthenticationConverterAdapter; -import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.ServerAuthenticationEntryPoint; -import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler; -import reactor.core.publisher.Mono; -/** - * @author: - */ -@AllArgsConstructor -@Configuration -@EnableWebFluxSecurity -public class ResourceServerConfig { - - private final ResourceServerManager resourceServerManager; - - @Bean - public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { - http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter()); - http.oauth2ResourceServer().authenticationEntryPoint(authenticationEntryPoint()); - http.authorizeExchange() - .anyExchange().access(resourceServerManager) - .and() - .exceptionHandling() - .accessDeniedHandler(accessDeniedHandler()) // 处理未授权 - .authenticationEntryPoint(authenticationEntryPoint()) //处理未认证 - .and().csrf().disable(); - return http.build(); - } - - /** - * 自定义未授权响应 - */ - @Bean - ServerAccessDeniedHandler accessDeniedHandler() { - return (exchange, denied) -> { - Mono mono = Mono.defer(() -> Mono.just(exchange.getResponse())) - .flatMap(response -> ResponseUtils.writeErrorInfo(response, ResultCode.ACCESS_UNAUTHORIZED)); - return mono; - }; - } - - /** - * token无效或者已过期自定义响应 - */ - @Bean - ServerAuthenticationEntryPoint authenticationEntryPoint() { - return (exchange, e) -> { - Mono mono = Mono.defer(() -> Mono.just(exchange.getResponse())) - .flatMap(response -> ResponseUtils.writeErrorInfo(response, ResultCode.TOKEN_INVALID_OR_EXPIRED)); - return mono; - }; - } - - @Bean - public Converter> jwtAuthenticationConverter() { - JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); - jwtGrantedAuthoritiesConverter.setAuthorityPrefix(SecurityConstants.AUTHORITY_PREFIX); - jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(SecurityConstants.JWT_AUTHORITIES_KEY); - - JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter(); - jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter); - return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter); - } -} \ No newline at end of file +//package com.recovery.gateway.security; +// +// +//import com.recovery.common.base.constant.SecurityConstants; +//import com.recovery.common.base.result.ResultCode; +//import com.recovery.gateway.util.ResponseUtils; +//import lombok.AllArgsConstructor; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.core.convert.converter.Converter; +//import org.springframework.security.authentication.AbstractAuthenticationToken; +//import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +//import org.springframework.security.config.web.server.ServerHttpSecurity; +//import org.springframework.security.oauth2.jwt.Jwt; +//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.ReactiveJwtAuthenticationConverterAdapter; +//import org.springframework.security.web.server.SecurityWebFilterChain; +//import org.springframework.security.web.server.ServerAuthenticationEntryPoint; +//import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler; +//import reactor.core.publisher.Mono; +///** +// * @author: +// */ +//@AllArgsConstructor +//@Configuration +//@EnableWebFluxSecurity +//public class ResourceServerConfig { +// +// private final ResourceServerManager resourceServerManager; +// +// @Bean +// public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { +// http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter()); +// http.oauth2ResourceServer().authenticationEntryPoint(authenticationEntryPoint()); +// http.authorizeExchange() +// .anyExchange().access(resourceServerManager) +// .and() +// .exceptionHandling() +// .accessDeniedHandler(accessDeniedHandler()) // 处理未授权 +// .authenticationEntryPoint(authenticationEntryPoint()) //处理未认证 +// .and().csrf().disable(); +// return http.build(); +// } +// +// /** +// * 自定义未授权响应 +// */ +// @Bean +// ServerAccessDeniedHandler accessDeniedHandler() { +// return (exchange, denied) -> { +// Mono mono = Mono.defer(() -> Mono.just(exchange.getResponse())) +// .flatMap(response -> ResponseUtils.writeErrorInfo(response, ResultCode.ACCESS_UNAUTHORIZED)); +// return mono; +// }; +// } +// +// /** +// * token无效或者已过期自定义响应 +// */ +// @Bean +// ServerAuthenticationEntryPoint authenticationEntryPoint() { +// return (exchange, e) -> { +// Mono mono = Mono.defer(() -> Mono.just(exchange.getResponse())) +// .flatMap(response -> ResponseUtils.writeErrorInfo(response, ResultCode.TOKEN_INVALID_OR_EXPIRED)); +// return mono; +// }; +// } +// +// @Bean +// public Converter> jwtAuthenticationConverter() { +// JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); +// jwtGrantedAuthoritiesConverter.setAuthorityPrefix(SecurityConstants.AUTHORITY_PREFIX); +// jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(SecurityConstants.JWT_AUTHORITIES_KEY); +// +// JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter(); +// jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter); +// return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter); +// } +//} \ No newline at end of file diff --git a/hoe-gateway/src/main/java/com/recovery/gateway/security/ResourceServerManager.java b/hoe-gateway/src/main/java/com/recovery/gateway/security/ResourceServerManager.java index 637e013..5a0c519 100644 --- a/hoe-gateway/src/main/java/com/recovery/gateway/security/ResourceServerManager.java +++ b/hoe-gateway/src/main/java/com/recovery/gateway/security/ResourceServerManager.java @@ -1,122 +1,79 @@ -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 { - private final RedisTemplate redisTemplate; - - @Setter - private List ignoreUrls; - - @Override - public Mono check(Mono 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)); -// } +//package com.recovery.gateway.security; // -// // 从redis中获取资源权限 -// Map urlPermRolesRules = redisTemplate.opsForHash().entries(GlobalConstants.URL_PERM_ROLES_KEY); -// List authorizedRoles = new ArrayList<>(); // 拥有访问权限的角色 -// boolean requireCheck = false; // 是否需要鉴权,默认未设置拦截规则不需鉴权 +//import cn.hutool.core.collection.CollectionUtil; +//import cn.hutool.core.convert.Convert; +//import cn.hutool.core.util.StrUtil; // -// // 获取当前资源 所需要的角色 -// for (Map.Entry permRoles : urlPermRolesRules.entrySet()) { -// String perm = permRoles.getKey(); -// if (pathMatcher.match(perm, restfulPath)) { -// List roles = Convert.toList(String.class, permRoles.getValue()); -// authorizedRoles.addAll(Convert.toList(String.class, roles)); -// if (requireCheck == false) { -// requireCheck = true; -// } -// } -// } +//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; // -// // 如果资源不需要权限 则直接返回授权成功 -// if (!requireCheck) { +//import java.util.ArrayList; +//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 { +// private final RedisTemplate redisTemplate; +// +// @Setter +// private List ignoreUrls; +// +// @Override +// public Mono check(Mono 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(); // -// // 判断JWT中携带的用户角色是否有权限访问 -// Mono authorizationDecisionMono = mono -// .filter(Authentication::isAuthenticated) -// .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; -// }) -// .map(AuthorizationDecision::new) -// .defaultIfEmpty(new AuthorizationDecision(false)); -// return authorizationDecisionMono; - } - - /** - * 跳过校验 - * - * @param path - * @return - */ - private boolean skipValid(String path) { - for (String skipPath : ignoreUrls) { - if (UrlPatternUtils.match(skipPath, path)) { - return true; - } - } - return false; - } -} \ No newline at end of file +// // 跳过token校验,放在这里去做是为了能够动态刷新 +//// if (skipValid(path)) { +// return Mono.just(new AuthorizationDecision(true)); +//// } +// } +// +// /** +// * 跳过校验 +// * +// * @param path +// * @return +// */ +// private boolean skipValid(String path) { +// for (String skipPath : ignoreUrls) { +// if (UrlPatternUtils.match(skipPath, path)) { +// return true; +// } +// } +// return false; +// } +//} \ No newline at end of file diff --git a/hoe-gateway/src/main/java/com/recovery/gateway/security/SecurityGlobalFilter.java b/hoe-gateway/src/main/java/com/recovery/gateway/security/SecurityGlobalFilter.java index 5dc9a9c..ff3fa02 100644 --- a/hoe-gateway/src/main/java/com/recovery/gateway/security/SecurityGlobalFilter.java +++ b/hoe-gateway/src/main/java/com/recovery/gateway/security/SecurityGlobalFilter.java @@ -1,62 +1,69 @@ -package com.recovery.gateway.security; - -import cn.hutool.core.util.StrUtil; - -import com.nimbusds.jose.JWSObject; -import com.recovery.common.base.constant.SecurityConstants; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.logging.log4j.util.Strings; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.core.Ordered; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.http.server.reactive.ServerHttpResponse; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; - -import java.net.URLEncoder; -/** - * Created with IntelliJ IDEA. - * - * @author: AI码师 关注公众号"AI码师"获取完整源码 - * @date: 2021/11/24 - * @description: - * @modifiedBy: - * @version: 1.0 - */ -@Component -@Slf4j -@RequiredArgsConstructor -public class SecurityGlobalFilter implements GlobalFilter, Ordered { - - @SneakyThrows - @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - - ServerHttpRequest request = exchange.getRequest(); - log.info("接受到请求地址:"+request.getURI()); - ServerHttpResponse response = exchange.getResponse(); - // 不是正确的的JWT不做解析处理 - String token = request.getHeaders().getFirst(SecurityConstants.AUTHORIZATION_KEY); - 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); - String payload = StrUtil.toString(JWSObject.parse(token).getPayload()); - request = exchange.getRequest().mutate() - .header(SecurityConstants.JWT_PAYLOAD_KEY, URLEncoder.encode(payload, "UTF-8")) - .build(); - exchange = exchange.mutate().request(request).build(); - return chain.filter(exchange); - } - - @Override - public int getOrder() { - return 0; - } -} \ No newline at end of file +//package com.recovery.gateway.security; +// +//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 lombok.RequiredArgsConstructor; +//import lombok.SneakyThrows; +//import lombok.extern.slf4j.Slf4j; +//import org.apache.logging.log4j.util.Strings; +//import org.springframework.cloud.gateway.filter.GatewayFilterChain; +//import org.springframework.cloud.gateway.filter.GlobalFilter; +//import org.springframework.core.Ordered; +//import org.springframework.data.redis.core.RedisTemplate; +//import org.springframework.http.server.reactive.ServerHttpRequest; +//import org.springframework.http.server.reactive.ServerHttpResponse; +//import org.springframework.stereotype.Component; +//import org.springframework.web.server.ServerWebExchange; +//import reactor.core.publisher.Mono; +// +//import java.net.URLEncoder; +///** +// * Created with IntelliJ IDEA. +// * +// * @author: AI码师 关注公众号"AI码师"获取完整源码 +// * @date: 2021/11/24 +// * @description: +// * @modifiedBy: +// * @version: 1.0 +// */ +//@Component +//@Slf4j +//@RequiredArgsConstructor +//public class SecurityGlobalFilter implements GlobalFilter, Ordered { +// +// @SneakyThrows +// @Override +// public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { +// +// ServerHttpRequest request = exchange.getRequest(); +// log.info("接受到请求地址:"+request.getURI()); +// ServerHttpResponse response = exchange.getResponse(); +// // 不是正确的的JWT不做解析处理 +// String token = request.getHeaders().getFirst(SecurityConstants.AUTHORIZATION_KEY); +// if (StrUtil.isBlank(token) || !StrUtil.startWithIgnoreCase(token, SecurityConstants.JWT_PREFIX)) { +// return chain.filter(exchange); +// } +// // 为请求追加 Same-Token 参数 +// request.mutate() +// // 为请求追加 Same-Token 参数 +// .header(SaSameUtil.SAME_TOKEN, SaSameUtil.getToken()) +// .build(); +// //结束 +// // 解析JWT获取jti,以jti为key判断redis的黑名单列表是否存在,存在则拦截访问 +// token = StrUtil.replaceIgnoreCase(token, SecurityConstants.JWT_PREFIX, Strings.EMPTY); +// String payload = StrUtil.toString(JWSObject.parse(token).getPayload()); +// request = exchange.getRequest().mutate() +// .header(SecurityConstants.JWT_PAYLOAD_KEY, URLEncoder.encode(payload, "UTF-8")) +// .build(); +// exchange = exchange.mutate().request(request).build(); +// return chain.filter(exchange); +// } +// +// @Override +// public int getOrder() { +// return 0; +// } +//} \ No newline at end of file diff --git a/pom.xml b/pom.xml index ad9c009..2c85a3f 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,16 @@ hutool-all ${hutool-version} + + + cn.dev33 + sa-token-redis-jackson + 1.37.0 + + + org.apache.commons + commons-pool2 +