更新时间:2018/11/9 11:35:53
更新内容:
1. 将 判断文件的可读权限和判断文件类型分别单独出一个文章;
2. 判断文件的可读权限做了api的扩展和代码优化,提供所有权限的判断。
以下正文:
最近做一个项目涉及到读取hdfs数据时要进行kerberos认证,上网找了挺多例子试了挺久才成功,项目完成了这里记录一下。因为时间过去挺久忘了当初是参考哪个博文验证成功的了,虽无法指明但表示感谢!
kerberos认证
这里是用keytab和krb5.conf文件进行kerberos认证,至于这两个文件是干嘛的自行搜索(其实我也不太清除o.o,就是用来验证Kerberos的了)。需要的相关信息配置在hdfs_info.properties文件中,配置如下:
## namenode的地址,hdfs://ip:port
hdfs_address=
## .keytab文件路径
key_tab_path=
## krb5.conf文件路径
krb5_path=
## hdfs-site.xml文件路径
hdfs_site_path=
## kerberos认证用户
login_user=
这里我只是列出了需要配置的内容,相关信息配置成自己集群环境的信息就好,hdfs-site.xml中主要是需要dfs.namenode.kerberos.principal和dfs.datanode.kerberos.principa这两个配置信息,如果不想将整个配置文件导入(里面配置了很多信息)也可以直接conf里面设置即可:
// ""中填写对应配置的值
conf.set("dfs.namenode.kerberos.principal","");
conf.set("dfs.datanode.kerberos.principal","");
然后Kerberos认证的类HdfsUtil.class中进行认证的方法kerberosCertify(),我将返回值由原来的void改为了Configuraiton,是想到kerberos认证是有过期时间的,不知道conf存储了认证信息,过期后是否需要重新认证,如果需要重新认证这样会方便写,且加个定时器定时去定时认证会更好,避免手动调用。如果不会过期那就还是void好点,且Configuration最好做单例处理,此处待确认和优化,具体代码如下:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.LocalFileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsAction;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.security.UserGroupInformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cdc.common.util.PropertiesUtil;
import com.cdc.hdfs.enums.FilePermissionEnum;
import com.cdc.hdfs.enums.FileTypeEnum;
/**
*@author lshua
*@time 2018年6月27日
*@description: 集群工具类
*/
public class HDFSUtil {
private static final Logger log = LoggerFactory.getLogger(HDFSUtil.class);
/**
* hdfs信息配置文件路径 resources目录下
*/
private static final String HDFS_INFO_ADDRESS = "hdfs_info.properties";
/**
* hdfs配置信息
*/
private static Map<String, String> proMap = PropertiesUtil.getProperties(HDFS_INFO_ADDRESS);
/**
* HDFS namenode地址
*/
private static final String HDFS_ADDRESS = proMap.get("hdfs_address");
/**
* 认证需要的.keytab文件的路径
*/
private static final String KEY_TAB_PATH = proMap.get("key_tab_path");
/**
* 配置文件krb5.conf的路径
*/
private static final String KRB5_PATH = proMap.get("krb5_path");
/**
* hdfs-site.xml文件的路径
*/
private static final String HDFS_SITE_PATH = proMap.get("hdfs_site_path");
/**
* kerberos认证用户名
*/
private static final String LOGIN_USER = proMap.get("login_user");
/**
* 配置信息
*/
private static Configuration conf = null;
/**
* 对集群进行认证操作
*
*@return Configuration 返回包含认证信息的,失败返回null
*@date 2018年11月2日
*/
public static Configuration kerberosCertify() {
conf = new Configuration();
// 设置kerberos配置信息
System.setProperty("java.security.krb5.conf", KRB5_PATH);
conf.set("fs.defaultFS", HDFS_ADDRESS);
conf.set("fs.hdfs.impl", DistributedFileSystem.class.getName());
conf.set("fs.file.impl", LocalFileSystem.class.getName());
/**
* 启用kerberos认证
*/
conf.setBoolean("hadoop.security.authentication", true);
conf.set("hadoop.security.authentication", "kerberos");
// 添加hdfs-site.xml的内容
conf.addResource(new Path(HDFS_SITE_PATH));
UserGroupInformation.setConfiguration(conf);
try {
// kerberos认证
UserGroupInformation.loginUserFromKeytab(LOGIN_USER, KEY_TAB_PATH);
UserGroupInformation.getLoginUser();
} catch (Exception e) {
log.error("------------hdfs kerberos 认证异常!--------------");
e.printStackTrace();
return null;
}
return conf;
}
代码中用到了一个自己写的PropertiesUtil.class工具类代码如下 :
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*@author lshua
*@time 2018年4月24日
*@description: 配置文件的工具类
*/
public class PropertiesUtil {
private static Logger log = LoggerFactory.getLogger(PropertiesUtil.class);
/**
*@description 根据文件路径获取配置信息
*@param confPath 配置文件路径
*@return Map<String, String>
*@author lshua
*@date 2018年5月4日
*/
public static Map<String, String> getProperties(String confPath) {
log.info("-----loadConfig()... begin-----");
log.info("-----confPath = {}", confPath);
Map<String, String> proMap = new HashMap<String, String>(32);
Properties prop = new Properties();
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
fis = new FileInputStream(new File(confPath));
bis = new BufferedInputStream(fis);
prop.load(bis);
Set<Entry<Object, Object>> propSet = prop.entrySet();
for(Entry<Object, Object> entry : propSet) {
proMap.put(entry.getKey().toString(), entry.getValue().toString());
}
} catch (Exception e) {
e.printStackTrace();
log.info("-----loadConf() error-----");
} finally {
try {
if(bis != null) {
bis.close(); bis = null;
}
if(fis != null) {
fis.close(); fis = null;
}
} catch (Exception e) {
log.info("------ close io stream error ! -----");
e.printStackTrace();
}
}
log.info("-----loadConfig()... end-----");
return proMap;
}
}
需要注意的是因为开启的kerberos认证,所以当其他地方需要做hdfs的相关操作的时候不能直接new 一个Configuration出来,需要使用这里进行了kerberos验证包含验证信息的Configuration,所以开发一个接口给其他代码获取就好:
/**
* 获取进行了kerberos认证的configuration
*
*@return Configuration
*@author lshua
*@date 2018年7月27日
*/
public static Configuration getConfiguration() {
return conf;
}
代码在项目中已经验证通过了的,这里就不贴测试的代码了。配置正常应该是能正常使用的,最后附上相关的jar包gradle依赖:
// hadoop相关依赖,编译时需要。
compileOnly('org.apache.hadoop:hadoop-common:2.6.0')
compileOnly('org.apache.hadoop:hadoop-hdfs:2.6.0')
// 日志
compile 'org.slf4j:slf4j-api:1.7.12'
compile 'log4j:log4j:1.2.17'
emmmmmm有时候还要环境数据,大概说一下:
* jdk 1.7
* eclipse 4.7.2
* gradle 4.4.10
* CDH5.8.3-hadoop2.6.0