进学阁

业精于勤荒于嬉,行成于思毁于随

0%

改造网关实现授权

前言:

先看下认证授权的过程,认证客户端的认证是最先被认证的,只有先认证客户端可会进行token的认证,而我们不应该把客户端的信息暴漏在外面所以客户端的信息只能通过网关转发的时候注入到请求中

直接请求认证服务器的流程

请求/oauth2/token 输入表单信息

Authorization设置为Basic Auth

获得结果

使用网关转发请求和注入服务的时候,当客户端不能直接提供客户端信息的时候,需要在网关转发时注入

改造网关

增加局部过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
@Component
public class LoginFilter extends AbstractGatewayFilterFactory<LoginFilter.Config> {
@Autowired
private ObjectMapper objectMapper;

@Autowired
private ClientProperties clientProperties;


public LoginFilter() {
super(Config.class);
}
/**
* Token URL 标识
*/
private static final String TOKEN_URL_IDENTIFY = "oauth2/token";

@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
try {
ServerHttpRequest request = exchange.getRequest();
//判断是否是请求token
String path = request.getURI().getPath();
if (!StrUtil.containsIgnoreCase(path, TOKEN_URL_IDENTIFY)) {
return chain.filter(exchange);
}
//TODO:后续可以增加验证码验证
//注入客户端信息
ServerHttpRequest.Builder mutate = request.mutate();
String clientStr =String.format("%s:%s",clientProperties.getClientId(),clientProperties.getClientSecret());
String base = Base64.encode(clientStr);
addHeader(mutate,"Authorization",String.format("Basic %s",base));
}catch (UnauthorizedException ex){
getErrResponse(exchange, AjaxResult.error(ResponseStatusEnum.UNAUTHORIZED,ex.getMessage()));
}catch (Exception e) {
return getErrResponse(exchange, AjaxResult.error(ResponseStatusEnum.SYS_ERROR, e.getMessage()));
}
return chain.filter(exchange);
};
}


public static class Config {
// 在这里可以定义配置属性
}

private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value)
{
if (value == null)
{
return;
}
String valueStr = value.toString();
String valueEncode = valueStr;
mutate.header(name, valueEncode);
}
private Mono<Void> getErrResponse(ServerWebExchange exchange, Object errInfo) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
return response.writeWith(Mono.create(monoSink -> {
try {
byte[] bytes = objectMapper.writeValueAsBytes(errInfo);
DataBuffer dataBuffer = response.bufferFactory().wrap(bytes);
monoSink.success(dataBuffer);
} catch (JsonProcessingException jsonProcessingException) {
log.error(jsonProcessingException.getMessage());
monoSink.error(jsonProcessingException);
}
}));
}

}

配置客户端信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "security.client")
public class ClientProperties {
private String clientId;
private String clientSecret;

public String getClientId() {
return clientId;
}

public void setClientId(String clientId) {
this.clientId = clientId;
}

public String getClientSecret() {
return clientSecret;
}

public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
}

1
2
3
4
security:
client:
clientId: messaging-client
clientSecret: secret

路由中添加过滤器

1
2
3
4
5
6
7
8
- id: luck-auth
uri: lb://luck-auth
predicates:
- Path=/auth/**
filters:
- StripPrefix=1
- CacheRequestFilter
- LoginFilter

测试:

总结:

Authorization设置为Basic Auth 的实际操作为在Header中新增一个key为Authorization value为 Basic +base64({clientId}:{clientSecret}) 。这里Basic后面是有一个空格的需要注意。