本来想用一节就写完SpringBootAdmin的,但随着研究的深入发现一节应该是不够的,网上的资料也不会非常系统,官网的例子有些已经好几年没更新了,所以接下来还是系统性的来写下吧
第一节 完成基础配置,暴露所有端点
第二节 给SpringBootAdmin的server端加入spring security安全控制
第三节 给SpringBootAdmin的clientr端加入spring security安全控制
第四节 配置SpringBootAdmin日志管理
第五节 配置SpringBootAdmin电子邮件通知
第六节 给SpringBootAdmin的client端加入jwt认证
在第三节中,我们给client加入了安全控制,密码是在配置文件中写死的。正如文章所说的,spring security的认证权限管理用于生产环境肯定是不能用这种方式的。比如我们会结合jwt认证实现前后端分离的认证管理,也会配合RBAC实现权限管理,这个具体可以参考sbvadmin专栏
那么接下来我们就尝试下在client中加入jwt认证该怎么做。
一、弃用spring.boot.admin.instance-auth.default-user-name
首先,之前我们server端一直用的固定账号和密码,这就要求所有的客户端都需要有同样的用户名密码进行下探,这个也是不合理的。移除spring.boot.admin.instance-auth.default-user-name
,我们可以自定义BasicAuthHttpHeaderProvider
来进行判断
注释掉default配置
# admin client account
#spring.boot.admin.instance-auth.default-user-name=client
#spring.boot.admin.instance-auth.default-password=client
重启,发现client报错401,显示down了。当然其实client并没有down
二、加入BasicAuthConfig类
@Configuration
public class BasicAuthConfig {
/**
* springboot自动装配默认实现类,由于需要对配置密码进行解码操作,故手动装配
*
* @return
*/
@Bean
public BasicAuthHttpHeaderProvider basicAuthHttpHeadersProvider() {
return new BasicAuthHttpHeaderProvider() {
@Override
public HttpHeaders getHeaders(Instance instance) {
HttpHeaders headers = new HttpHeaders();
//获取用户名,密码
String username = instance.getRegistration().getMetadata().get("user.name");
String password = instance.getRegistration().getMetadata().get("user.password");
String type = instance.getRegistration().getMetadata().get("user.type");
//若是token有值,那么使用token认知
if ("token".equalsIgnoreCase(type)) {
headers.set("X-Token",password);
} else if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
headers.set(HttpHeaders.AUTHORIZATION, encode(username, password));
}
return headers;
}
protected String encode(String username, String password) {
String token = Base64Utils.encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));
return "Basic " + token;
}
};
}
}
这个配置类还是比较清晰的,我们要关心的就是用户名密码或者token的来源,这个需要在client端进行配置
三、配置client端元数据
在client端的application.properties中加入源数据配置
# for server auth
spring.boot.admin.client.instance.metadata.user.name=${spring.security.user.name}
spring.boot.admin.client.instance.metadata.user.password=${spring.security.user.password}
这里的用户名密码可以取自客户端的账号体系,我们这里先用之前配置的默认账号密码。
重新启动,已经可以了。同时我们看到了元数据一栏里面,有了user.name和user.password。
以上基本上完成了server端和client端的认证配置,但目前用的认证方式是Basic的请求方式,下面我们解决下使用了复杂的认证方式的情况,比如配合jwt认证。
四、client配置jwt认证
这块怎么做就不过多说明了,有兴趣的同学可以去看第四节 springsecurity结合jwt实现前后端分离开发。接下来修改下BasicAuthConfig
就可以了。
...
//获取用户名,密码
String username = instance.getRegistration().getMetadata().get("user.name");
String password = instance.getRegistration().getMetadata().get("user.password");
String type = instance.getRegistration().getMetadata().get("type");
String token = instance.getRegistration().getMetadata().get("token");
//若是token有值,那么使用token认知
if ("token".equalsIgnoreCase(type)) {
headers.set(HttpHeaders.AUTHORIZATION,token);
} else if ("jwt".equalsIgnoreCase(type)) {
Date expired = JwtTokenUtil.getExpiredDate(86400);
Map<String, Object> map = new HashMap<>();
map.put("authorities", "admin"); // 配置用户角色
map.put("uid",2); // 配置用户id
String jwt = JwtTokenUtil.genToken(map,username,expired,"sbvadmin");
headers.set(HttpHeaders.AUTHORIZATION, jwt);
}else if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
headers.set(HttpHeaders.AUTHORIZATION, encode(username, password));
}
return headers;
...
主要就是jwt那段代码,JwtTokenUtil功能大同小异,自己调整下就好了。 好了基本完成了。
如果client端配置了rabbitmq, 被spring boot
admin监控后,client一旦启动就会去检查rabbitmq的连接,如果连接有问题就会报错。这点要注意。