spring、springboot整合hadoop的时候出现的权限问题

相信大家在使用spring、springboot整合hadoop的时候,操作权限的时候可能会遇到下面这样一个权限异常。不过解决的方式有多种,我这里列出两种比较好的解决问题的方案。

Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.AccessControlException): Permission denied: user=hwf, access=WRITE, inode="/mydir3":hdfs:hdfs:drwxr-xr-x

spring、springboot整合hadoop的时候出现的权限问题_第1张图片意思其实就是我们在本机操作的时候,默认是本机用户去我们HDFS系统操作,比如上传,这个时候我们本机用户在HDFS系统上面是没有权限的,这个时候就会报出上面那个错误。

经过对源码一步一步跟踪,发现在org.apache.hadoop.security.UserGroupInformation这个类中看出了端倪。在这个类的commit方法中,核心代码为下面这个

//If we don't have a kerberos user and security is disabled, check
//if user is specified in the environment or properties
if (!isSecurityEnabled() && (user == null)) {
  String envUser = System.getenv(HADOOP_USER_NAME);
  if (envUser == null) {
    envUser = System.getProperty(HADOOP_USER_NAME);
  }
  user = envUser == null ? null : new User(envUser);
}
// use the OS user
if (user == null) {
  user = getCanonicalUser(OS_PRINCIPAL_CLASS);
  if (LOG.isDebugEnabled()) {
    LOG.debug("using local user:"+user);
  }
}
// if we found the user, add our principal
if (user != null) {
  if (LOG.isDebugEnabled()) {
    LOG.debug("Using user: \"" + user + "\" with name " + user.getName());
  }

  User userEntry = null;
  try {
    userEntry = new User(user.getName());
  } catch (Exception e) {
    throw (LoginException)(new LoginException(e.toString()).initCause(e));
  }
  if (LOG.isDebugEnabled()) {
    LOG.debug("User entry: \"" + userEntry.toString() + "\"" );
  }

  subject.getPrincipals().add(userEntry);

大致意思就是,如果没有设置kerberos用户就获取系统环境用户,最后伪装成User进行登录,而且new User(envUser)我们只需要一个用户名即可,可以设置在HADOOP_USER_NAME这个里面。那么设想一下,如果我们在程序获取系统环境变量HADOOP_USER_NAME之前给他设置成我们HDFS的那个有权限的用户,是不是这样就可以了呢。

然后进行设计,那么我们就写一个BeanFactoryPostProcessor吧,在这个类里面注入这个属性的值。这样直接

System.setProperty("HADOOP_USER_NAME" , "hdfs");可以解决问题。但是问题来了,我们需要把这两个值配置起来,于是有了下面的代码:
@Value("${HADOOP_USER_NAME_KEY}")
private String HADOOP_USER_NAME_KEY;

@Value("${HADOOP_USER_NAME}")
private String HADOOP_USER_NAME;

但是在程序里面拿不到这个值,System.setProperty(HADOOP_USER_NAME_KEY , HADOOP_USER_NAME);

确实BeanFactoryPostProcessor是在所有初始化bean之前,执行的,这个时候spring并没有帮我们把xml装配成一个一个bean,属性文件也没有解析,那么怎么办呢?

这个时候我们可以实现InitializingBean,问题轻松解决,代码也变得足够优雅了。

 

其实,如果仔细看过hadoop官网的小伙伴,应该知道另外一种解决方案!

Proxy user - Superusers Acting On Behalf Of Other Users

没错,就是通过动态创建代理的方式!但是这种方式需要在hadoop的core-site.xml中配置一点东西,比如我这里的用户是

hwf,那么,可以按照下面这样配置。下面的配置权限相对比较宽松,这样我本地的用户hwf就能够在任何域名下或者在任何组里面都能够扮演想要成为的角色。

   
     hadoop.proxyuser.hwf.hosts
     *
   
   
     hadoop.proxyuser.hwf.groups
     *
   

比如我这里扮演的还是用户hdfs,这个时候可以在程序里面设置。

UserGroupInformation ugi =
        UserGroupInformation.createProxyUser("hdfs", UserGroupInformation.getLoginUser());
ugi.doAs(new PrivilegedExceptionAction() {
             public Void run() throws Exception {
                 //写你的逻辑
             }
});

同样,这种方式也能解决问题!

最后,欢迎热爱技术的小伙伴加入我们的聊天群qq:715115302

你可能感兴趣的:(大数据,hadoop,实战应用)