refactor:项目结构优化

This commit is contained in:
haoxr 2020-11-17 09:30:01 +08:00
parent 9a0a62d89b
commit 2b87d5b1c1
9 changed files with 120 additions and 145 deletions

View File

@ -70,7 +70,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
// refresh token有两种使用方式重复使用(true)非重复使用(false)默认为true
// 1 重复使用access token过期刷新时 refresh token过期时间未改变仍以初次生成的时间为准
// 2 非重复使用access token过期刷新时 refresh token过期时间延续在refresh token有效期内刷新便永不失效达到无需再次登录的目的
.reuseRefreshTokens(false);
.reuseRefreshTokens(true);
}
/**

View File

@ -4,20 +4,24 @@ import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@AllArgsConstructor
public class WxConfig {
private WxProperties properties;
@Value("${wx.miniapp.appid}")
private String appid;
@Value("${wx.miniapp.secret}")
private String secret;
@Bean
public WxMaConfig wxMaConfig() {
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
config.setAppid(properties.getAppid());
config.setSecret(properties.getSecret());
config.setAppid(appid);
config.setSecret(secret);
return config;
}

View File

@ -1,22 +0,0 @@
package com.youlai.auth.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxProperties {
/**
* 设置微信小程序的appid
*/
private String appid;
/**
* 设置微信小程序的Secret
*/
private String secret;
}

View File

@ -6,6 +6,8 @@ import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.youlai.auth.domain.Oauth2Token;
import com.youlai.common.core.constant.AuthConstants;
import com.youlai.common.core.constant.Constants;
@ -20,6 +22,7 @@ import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.logging.log4j.util.Strings;
import org.springframework.data.redis.core.RedisTemplate;
@ -31,7 +34,9 @@ import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import javax.servlet.http.HttpServletRequest;
import java.security.KeyPair;
import java.security.Principal;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@ -39,6 +44,7 @@ import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/oauth")
@AllArgsConstructor
@Slf4j
public class AuthController {
private TokenEndpoint tokenEndpoint;
@ -46,6 +52,7 @@ public class AuthController {
private WxMaService wxService;
private UmsMemberFeignClient umsMemberFeignClient;
private PasswordEncoder passwordEncoder;
private KeyPair keyPair;
@ApiOperation("OAuth2认证生成token")
@ -66,7 +73,7 @@ public class AuthController {
@ApiIgnore Principal principal,
@ApiIgnore @RequestParam Map<String, String> parameters
) throws HttpRequestMethodNotSupportedException, WxErrorException {
log.info("生成token开始");
String clientId = parameters.get("client_id");
if (StrUtil.isBlank(clientId)) {
@ -74,8 +81,8 @@ public class AuthController {
}
// 微信小程序端认证处理
if(AuthConstants.WEAPP_CLIENT_ID.equals(clientId)){
return this.handleForWxAppAuth(principal,parameters);
if (AuthConstants.WEAPP_CLIENT_ID.equals(clientId)) {
return this.handleForWxAppAuth(principal, parameters);
}
OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
@ -162,4 +169,11 @@ public class AuthController {
}
@GetMapping("/public_key")
public Map<String, Object> getKey() {
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey).build();
return new JWKSet(key).toJSONObject();
}
}

View File

@ -1,29 +0,0 @@
package com.youlai.auth.controller;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.KeyPair;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
/**
* RSA公钥开放接口
*/
@RestController
@AllArgsConstructor
public class PublicKeyController {
private KeyPair keyPair;
@GetMapping("/rsa/publicKey")
public Map<String, Object> getKey() {
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey).build();
return new JWKSet(key).toJSONObject();
}
}

View File

@ -1,36 +0,0 @@
package com.youlai.gateway.component;
import cn.hutool.json.JSONUtil;
import com.youlai.common.core.result.Result;
import com.youlai.common.core.result.ResultCode;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
/**
* 无权访问自定义响应
*/
@Component
public class CustomServerAccessDeniedHandler implements ServerAccessDeniedHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException e) {
ServerHttpResponse response=exchange.getResponse();
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin","*");
response.getHeaders().set("Cache-Control","no-cache");
String body= JSONUtil.toJsonStr(Result.custom(ResultCode.USER_ACCESS_UNAUTHORIZED));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer));
}
}

View File

@ -1,37 +0,0 @@
package com.youlai.gateway.component;
import cn.hutool.json.JSONUtil;
import com.youlai.common.core.result.Result;
import com.youlai.common.core.result.ResultCode;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
/**
* 无效token/token过期 自定义响应
*/
@Component
public class CustomServerAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
@Override
public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException e) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
String body = JSONUtil.toJsonStr(Result.custom(ResultCode.TOKEN_INVALID_OR_EXPIRED));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer));
}
}

View File

@ -2,24 +2,37 @@ package com.youlai.gateway.config;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
import com.youlai.common.core.constant.AuthConstants;
import com.youlai.gateway.component.AuthorizationManager;
import com.youlai.gateway.component.CustomServerAccessDeniedHandler;
import com.youlai.gateway.component.CustomServerAuthenticationEntryPoint;
import com.youlai.common.core.result.Result;
import com.youlai.common.core.result.ResultCode;
import com.youlai.gateway.security.AuthorizationManager;
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.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
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.core.AuthenticationException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
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.authentication.ServerAuthenticationFailureHandler;
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
/**
* 资源服务器配置
*/
@ -29,34 +42,101 @@ import reactor.core.publisher.Mono;
public class ResourceServerConfig {
private AuthorizationManager authorizationManager;
private CustomServerAccessDeniedHandler customServerAccessDeniedHandler;
private CustomServerAuthenticationEntryPoint customServerAuthenticationEntryPoint;
private WhiteListConfig whiteListConfig;
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http.oauth2ResourceServer().jwt()
.jwtAuthenticationConverter(jwtAuthenticationConverter());
// 自定义处理JWT请求头过期或签名错误的结果
http.oauth2ResourceServer().authenticationEntryPoint(customServerAuthenticationEntryPoint);
http.oauth2ResourceServer().authenticationEntryPoint(serverAuthenticationEntryPoint());
//http.formLogin().authenticationFailureHandler(serverAuthenticationFailureHandler());
http.authorizeExchange()
.pathMatchers(ArrayUtil.toArray(whiteListConfig.getUrls(),String.class)).permitAll()
.pathMatchers(ArrayUtil.toArray(whiteListConfig.getUrls(), String.class)).permitAll()
.anyExchange().access(authorizationManager)
.and()
.exceptionHandling()
.accessDeniedHandler(customServerAccessDeniedHandler) // 处理未授权
.authenticationEntryPoint(customServerAuthenticationEntryPoint) //处理未认证
.accessDeniedHandler(accessDeniedHandler()) // 处理未授权
.authenticationEntryPoint(serverAuthenticationEntryPoint()) //处理未认证
.and().csrf().disable();
return http.build();
}
/**
* 未授权
*
* @return
*/
@Bean
ServerAccessDeniedHandler accessDeniedHandler() {
return (exchange, denied) -> {
Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
.flatMap(response -> {
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
String body = JSONUtil.toJsonStr(Result.custom(ResultCode.USER_ACCESS_UNAUTHORIZED));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer))
.doOnError(error -> DataBufferUtils.release(buffer));
});
return mono;
};
}
/**
* token无效或者已过期
*
* @return
*/
@Bean
ServerAuthenticationEntryPoint serverAuthenticationEntryPoint() {
return (exchange, e) -> {
Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
.flatMap(response -> {
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
String body = JSONUtil.toJsonStr(Result.custom(ResultCode.TOKEN_INVALID_OR_EXPIRED));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer))
.doOnError(error -> DataBufferUtils.release(buffer));
});
return mono;
};
}
@Bean
ServerAuthenticationFailureHandler serverAuthenticationFailureHandler() {
return (exchange, e) -> {
Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getExchange().getResponse()))
.flatMap(response -> {
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
String body = JSONUtil.toJsonStr(Result.custom(ResultCode.TOKEN_INVALID_OR_EXPIRED));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer))
.doOnError(error -> DataBufferUtils.release(buffer));
});
return mono;
};
}
/**
* @return
* @link https://blog.csdn.net/qq_24230139/article/details/105091273
* ServerHttpSecurity没有将jwt中authorities的负载部分当做Authentication
* 需要把jwt的Claim中的authorities加入
* 方案重新定义ReactiveAuthenticationManager权限管理器默认转换器JwtGrantedAuthoritiesConverter
* @return
*/
@Bean
public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
@ -69,4 +149,5 @@ public class ResourceServerConfig {
return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
}
}

View File

@ -1,4 +1,4 @@
package com.youlai.gateway.component;
package com.youlai.gateway.security;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;