最近在使用nacos,部署在k8s集群上,使用的是从源码自己打的镜像。在配置nacos的权限认证功能时, 发现无法生效,而且所谓的配置修改立即生效也无法实现,下面就探讨下这是什么原因导致的?同时也看下nacos所说配置修改立即生效是如何实现的?

基于nacos-1.3.3

nacos的权限控制是什么样的

nacos通过将用户绑定到某个角色上,然后赋予某个角色对某个资源(命名空间)的读写权限,假如当前登录的用户对某个空间没有访问权限,那么其试图访问该资源时,会通过弹框等方式予以拒绝,大致是这样的…
在这里插入图片描述

nacos是如何进行权限控制的

nacos的权限控制在AuthFilter中实现

com.alibaba.nacos.core.auth.AuthFilter#doFilter

// 被加上@Secured注解,并且auth鉴权开关打开了,将进行权限校验
if (method.isAnnotationPresent(Secured.class) && authConfigs.isAuthEnabled()) {
                
    if (Loggers.AUTH.isDebugEnabled()) {
        Loggers.AUTH.debug("auth start, request: {} {}", req.getMethod(), req.getRequestURI());
    }
    
	// 获取需要权限认证的方法, 和请求进行校验
    Secured secured = method.getAnnotation(Secured.class);
    String action = secured.action().toString();
    String resource = secured.resource();
    
    if (StringUtils.isBlank(resource)) {
        ResourceParser parser = secured.parser().newInstance();
        resource = parser.parseName(req);
    }
    
    if (StringUtils.isBlank(resource)) {
        // deny if we don't find any resource:
        throw new AccessException("resource name invalid!");
    }
	// 正真进行权限校验的地方,对当前用户及其角色的进行权限验证
    authManager.auth(new Permission(resource, action), authManager.login(req)); 
}

当方法被加上Secured注解即意味着该方法需要进行权限校验,比如"/nacos/v1/console/namespaces",其实现

@PostMapping
@Secured(action = ActionTypes.WRITE, parser = ConfigResourceParser.class)
public Boolean publishConfig(HttpServletRequest request...)

权限校验的方式并不复杂,具体就是首先获取当前登录用户的所有角色(查询roles表),如果角色具有全局的ROLE_ADMIN角色,则校验通过;
其次校验其访问的命名空间,最后查询当前用于持有的角色在permissions表中被赋予的权限,并和"@Secured"注解赋予的action权限进行对比

开启权限控制的开关

auth开关的读取是通过 ReloadableConfigs实现的,ReloadableConfigs的实现其实就是启动定时任务,不断的读取appliaction.properties的配置并更新至内存

public class ReloadableConfigs {
    
    private static final String FILE_PREFIX = "file:";
    
    private Properties properties;
    
    @Value("${spring.config.location:}")
    private String path;
    
    /**
     * Periodically load configuration file information.
     *
     * @throws IOException IOException
     */
    @Scheduled(fixedRate = 5000)
    public void reload() throws IOException {
        final Properties properties = new Properties();
        InputStream inputStream = null;
        if (StringUtils.isNotBlank(path) && path.contains(FILE_PREFIX)) {
            String[] paths = path.split(",");
            path = paths[paths.length - 1].substring(FILE_PREFIX.length());
        }
        try {
            inputStream = new FileInputStream(new File(path + "application.properties"));
        } catch (Exception ignore) {
        }
        if (inputStream == null) {
            inputStream = getClass().getResourceAsStream("/application.properties");
        }
        properties.load(inputStream);
        inputStream.close();
        this.properties = properties;
    }
    
    public final Properties getProperties() {
        return properties;
    }
}

从"spring.config.location"配置的路径下读取配置,如果文件不存在则试图读取classPath下的文件

为什么权限控制开关失效

为什么在application.properties中将nacos.core.auth.enabled=true打开,为什么当时的auth功能失效了?
在程序启动后,通过arthas读取com.alibaba.nacos.core.env.ReloadableConfigs#getProperties发现配置不变
原因就是没有读取到application.properties
首先,ReloadableConfigs#reloadspring.config.location配置在哪儿? 在程序启动脚本中是这样的

export DEFAULT_SEARCH_LOCATIONS="classpath:/,classpath:/config/,file:./,file:./conf/"
export CUSTOM_SEARCH_LOCATIONS=${BASE_DIR}/init.d/,file:${BASE_DIR}/conf/,${DEFAULT_SEARCH_LOCATIONS}

...
JAVA_OPT="${JAVA_OPT} --spring.config.location=${CUSTOM_SEARCH_LOCATIONS}"

...
$JAVA ${JAVA_OPT} > ${BASE_DIR}/logs/start.out

而reload方法默认读取的路径是最后一个路径下的配置,如果配置不当,那么该路径下没有文件,自然就无法读取到

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐