您的位置:首页 > 其它

基于客户端(浏览器)证书身份认证的方法

2012-08-31 10:56 555 查看
1、介绍

通过证书验证用户身份(浏览器),其核心是利用cookie实现http和https的信息共享(同域名)。如http://test.abc.com/app/index.html 发现未验证后,跳转到https://test.abc.com:443/app/checkCrt.html身份验证,要求出去证书,确认后将身份信息带入http请求头部,跳转到原请求页面(http://test.abc.com/app/index.html ),读取身份信息后进入页面(出于安全考虑Cookie需要加密)。

流程图



流程说明:

登录流程详细介绍:
1). 未登录用户访问页面 如:http://test.abc.com/app/index.html
2). 【CertAuthValve】判断是否访问受限制资源,如访问受限制的资源则判断用户身份是否已验证,未验证则将用户重定向到身份验证页面,原始请求的url做为
query的一部分,登录成功后可以跳转回来, 如:https://test.abc.com:443/app/checkCrt.htm?done=/index.html。
3). 【CertAuthValve】对于https请求,apache读取请求提供的用户证书,获取证书中的邮件地址,并将该信息写入请求头中。
4). 【GetUserInfoValve】读取请求头,获取刚刚设置的用户邮件地址信息,进一步获取用户的详细信息,然后将这些信息加密后放入cookie中。
5). 登录完成,将用户外部重定向回原始页面。

2、具体实现

1)、安装apache、ssh、java、jboss等环境,略。

2)、生成服务证书和服务密码

openssl req -new -x509 -nodes -out /home/admin/app/conf/ssl.crt/server.crt -keyout /home/admin/app/conf/ssl.crt/server.key -days 3600

因为要和内网证书交互,所以需要一个内网证书公钥文件,可以通过以下方式获取:
获取方法:IE->工具->Internet选项->内容->证书->受信任的根证书颁发机构,找到intranet行,点击导出,选择下一步,选择Base64编码X.509,将证书文件保存为intranet-ca.crt,拷贝到目录/home/admin/app/conf/ssl.crt/。

3)、apache(httpd.conf)配置

应用和身份验证页面放在一起,所以需要同时配置两个虚拟主机,同时监听80(处理http请求)、443(处理https请求)端口。

#监听端口

Listen 80

Listen 443

#app的虚拟主机配置

NameVirtualHost *:80
<VirtualHost *:80>
ServerAdmin sa@abc.com
ServerName test.abc.com
DocumentRoot /home/admin/app/target/app/htdocs/
</VirtualHost>

#身份验证的虚拟主机配置

NameVirtualHost *:443
<VirtualHost *:443>
ServerAdmin sa@abc.com
ServerName test.abc.com
DocumentRoot /home/admin/app/target/app/htdocs/

SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+SSLv3:+EXP:+eNULL

#该指令为虚拟主机指定证书文件名。

SSLCertificateFile /home/admin/app/conf/ssl.crt/server.crt

#该指令为证书指定一个对应的私钥文件

SSLCertificateKeyFile /home/admin/app/conf/ssl.crt/server.key

#该指令为指定一个包含Certificate Authority证书的文件

#证书公钥

SSLCACertificateFile /home/admin/app/conf/ssl.crt/intranet-ca.cer

SSLProxyEngine on
RewriteEngine on
#设置客户端证书验证为必须
SSLVerifyClient require

#因为一个CA证书能够被另一个CA证书验证,所以可以形成一个CA证书链.使用该指令可指定服务器验证用户证书时可以查找多少个CA证明。
#设置认证深度:一般用默认10。

SSLVerifyDepth 10

#把mod_ssl里的变量变为全局环境的变量
SSLOptions +StdEnvVars

#将证书中的邮件地址添加到请求头中

RequestHeader unset SSL_CLIENT_S_DN_Email
RequestHeader add SSL_CLIENT_S_DN_Email %{SSL_CLIENT_S_DN_Email}e
</VirtualHost>

4)、代码片段

//CertAuthValve.java

//判断session中是否有用户邮箱地址

SessionValue session = SessionHelper.getSessionValue(rundata);

if (StringUtil.isNotEmpty(session.getCropEmail())) {

return null;

}

// 从内网证书中获取用户邮箱地址: SSL_CLIENT_S_DN_Email

String cropEmail = rundata.getRequest().getHeader(SSL_CLIENT_HEADER_MAIL);

if (StringUtil.isNotEmpty(cropEmail)) {

//将邮箱地址保存到session

session.setCropEmail(cropEmail);

SessionHelper.saveSessionValue(rundata, session);

if (log.isDebugEnabled()) {

log.debug("用户" + session.getCropEmail() + "已经通过证书验证");

}

return null;

}

URIBrokerService uriBrokerService = (URIBrokerService) getWebxComponent().getService(

URIBrokerService.SERVICE_NAME);

URIBroker noPermissionUriBroker = uriBrokerService.getURIBroker(CHECK_CRT_URL);

//请求的原始URL & 验证的URL

String requestPath = rundata.getPathInfo().replace("_", "");

String checkCrtUrl = (String) noPermissionUriBroker.getPath().get(

noPermissionUriBroker.getPath().size() - 1);

try {

//原始请求判断

if (requestPath.equalsIgnoreCase(checkCrtUrl)) {

//当前是https请求,但是依然不能得到证书信息,转到禁止页面

//(要将禁止页面加入到允许访问的配置文件中,不然会导致循环重定向)

URIBroker uriBroker = uriBrokerService.getURIBroker("forbidden");

rundata.setRedirectLocation(uriBroker.render());

} else {

//转到证书验证页面

rundata.setRedirectLocation(noPermissionUriBroker.render() + "?done=" + rundata.getPathInfo());

}

} catch (IOException e) {

log.error("权限验证重定向出错", e);

}

return new BreakPipeline();

//GetUserInfoValve.java

Object user = rundata.getSession().getAttribute("userInfo");

if (user == null) {

SessionValue session = SessionHelper.getSessionValue(rundata);

String email = session.getCropEmail();

Employe employe = PersonInfoUtil.getPersonInfoByEmail(email);

// 写入cookie

session.setEmployeeId(employe.getEmployeId());

session.setName(employe.getName());

session.setCropEmail(employe.getEmail());

SessionHelper.saveSessionValue(rundata, session);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐