Blog信息 |
blog名称: 日志总数:1304 评论数量:2242 留言数量:5 访问次数:7587000 建立时间:2006年5月29日 |

| |
[J2SE]JAAS:认证篇 软件技术
lhwork 发表于 2006/8/18 16:51:23 |
JAAS:认证篇基础:
JAAS是JAVA安全中的重要部分.
一般谈到的Java安全包会涉及到JAAS,JCE,JSSE等.
Java Authentication and Authorization Service (JAAS): A framework for user-based authentication
Java Cryptography Extension (JCE): A framework for using strong ciphers on a global basis
Java Secure Socket Extension (JSSE): An extension for SSL and Transport Layer Security (TLS) support
JAAS 中几个比较常见的 classes http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.html 普通对象
Subject
Principals
Credentials
身份验证相关的对象
LoginContext
LoginModule
CallbackHandler
Callback
权限管控相关的对象
Policy
AuthPermission
PrivateCredentialPermission
跟认证有关系的主要是:普通对象 和身份验证相关的对象 .
Tomcat作为学习JAAS,不失为比较方便的web容器.
Tomcat有Realm的概念[参见Apache Tomcat官方网站].
Standard Realm Implementations
JDBCRealmDataSourceRealmJNDIRealmMemoryRealmJAASRealm
所谓Realm是跟j2EE安全规范相关的,先介绍一下安全规范 Web层面.看下面的web.xml配置片段.
<security-constraint> <web-resource-collection> <web-resource-name>User Protected</web-resource-name> <url-pattern>/protected/*</url-pattern> <url-pattern>/protected.jsp</url-pattern> </web-resource-collection> <auth-constraint> <role-name>*</role-name> </auth-constraint> </security-constraint> <!--<login-config> <auth-method>BASIC</auth-method> <realm-name>MyJAASRealm</realm-name> </login-config>--> <!-- Default login configuration uses form-based authentication --> <login-config> <auth-method>FORM</auth-method> <realm-name>Anonymous Form-Based Authentication Area</realm-name> <form-login-config> <form-login-page>/protected/login.jsp</form-login-page> <form-error-page>/protected/error.jsp</form-error-page> </form-login-config> </login-config> <!-- Security roles referenced by this web application --> <security-role> <role-name>*</role-name> </security-role>
其中:具体说明可参见Servlet与JSP权威指南(More Servlets and Java Server Pages)一书,有乐于助人将第五章公布于网上,也可参见第9节[提供安全性],此处不再赘述.
在Tomcat中,Realm将对页面提交后的登录进行后续工作,也就是说你的user,role的关系可以存在于配置文件,数据库,LDAP[通过JNDI来配置].而选择的方法可以是
JDBCRealmDataSourceRealmJNDIRealmMemoryRealmJAASRealm
使用JAASRealm,很简单>
步骤一:
实现LoginModule.
package cn.com.tiansky.auth.LoginModule;
import java.io.IOException;import java.sql.Connection;import java.sql.ResultSet;import java.sql.Statement;import java.util.Map;
import javax.naming.Context;import javax.naming.InitialContext;import javax.security.auth.Subject;import javax.security.auth.callback.Callback;import javax.security.auth.callback.CallbackHandler;import javax.security.auth.callback.NameCallback;import javax.security.auth.callback.PasswordCallback;import javax.security.auth.callback.UnsupportedCallbackException;import javax.security.auth.login.LoginException;import javax.security.auth.spi.LoginModule;import javax.sql.DataSource;import org.apache.log4j.Logger;import cn.com.tiansky.auth.Principal.Operator;import cn.com.tiansky.tool.MD5;
/** * MySampleModule,A sample LoginModule * * @author tiansky * @version 1.0 */public class MySampleModule implements LoginModule {
private Subject _subject;
private CallbackHandler _ch;
private Map _sharedState;
private Map _options;
private String _jndi;
private Operator _op = null;
private String _mark;
private String username;
private String password;
private static Logger log = Logger.getLogger(MySampleModule.class);
private boolean _debug = false;
/** * @param arg0 * @param arg1 * @param arg2 * @param arg3 */ public void initialize(Subject arg0, CallbackHandler arg1, Map arg2, Map arg3) { this._subject = arg0; this._ch = arg1; this._sharedState = arg2; this._options = arg3; if (_options.containsKey("jndi")) { _jndi = (String) _options.get("jndi"); } if (_options.containsKey("mark")) { _mark = ((String) _options.get("mark")); } if (_options.containsKey("debug")) { _debug = "true".equalsIgnoreCase((String) _options.get("debug")); } }
public boolean login() throws LoginException {
if (_ch == null) throw new LoginException("获取认证信息的CallbackHandler为空,无法获取认证信息");
Callback[] callbacks = new Callback[2]; callbacks[0] = new NameCallback("userid: "); callbacks[1] = new PasswordCallback("password: ",false); log.info("开始获取认证信息..."); try {
_ch.handle(callbacks); username = ((NameCallback) callbacks[0]).getName(); // new String(latin.getBytes("iso-8859-1"),"gbk"); log.debug("转码"+username); final char[] passwordcontents; passwordcontents = ((PasswordCallback) callbacks[1]).getPassword(); password = new String(passwordcontents); if (_debug) { log.debug("[username]=" + username); log.debug("[password]=" + password); }
if (password == null) { password = ""; }
if ("PLAIN".equals(_mark)) { ;// do nothing } else if ("MD5".equals(_mark)) { try { password = MD5.encrypt(password); log.debug("md5password" + password); } catch (Exception e) { log.warn("MD5加密出错", e); throw new LoginException("MD5加密出错"); }
} else if ("DES".equals(_mark)) { ;// add some des encrypt process } else { throw new LoginException("无法识别的加密算法:" + _mark); }
if (_debug) { log.debug("[password(after encrypt)]=" + password); }
//((PasswordWebCallback) callbacks[1]).clearPassword();
} catch (UnsupportedCallbackException uce) { throw new LoginException("未知的callback类型: " + uce.getCallback().toString()); } catch (IOException e) { throw new LoginException("未知的IO错误."); } try { if(checkuser(username,password)==1) { log.info("成功获得登录信息"); return true; } else { log.error("帐号或密码错误"); } } catch(Exception e) { log.error("查询帐号[数据库操作异常]",e); throw new LoginException("查询帐号[数据库操作异常]."); } return false; }
public boolean logout() throws LoginException { _subject.getPrincipals().clear(); return true; }
public boolean abort() throws LoginException {
log.info("放弃登录."); logout(); return true; }
public boolean commit() throws LoginException { _subject.getPrincipals().add(_op); if (_debug) { log.info("用户所属组:" + _subject.getPrincipals()); }
// in any case, clean out state username = null; password = null; log.info("授权成功."); return true; }
private int checkuser(String user, String pwd) throws Exception { int rei = 0; // Obtain our environment naming context log.debug("Obtain our environment naming context"); Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env");
// Look up our data source DataSource ds = (DataSource) envCtx.lookup(this._jndi); log.debug("获取ds成功!"); // Allocate and use a connection from the pool Connection conn = ds.getConnection(); log.debug("获取conn成功!"); // ... use this connection to access the database ... String sql = "select OPERATORID from operator where OPERATORLOGINNAME='" + user + "' and OPERATORPASSWORD='" + pwd + "' "; log.debug("sql!= "+sql); Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(sql); if (rs.next()) { String oid = rs.getString("OPERATORID"); _op = new Operator(oid); _op.setName("操作员"); _op.setLoginname(user); _op.setPwd(pwd); rei = 1; } else { System.out.println("帐号不存在或密码错误!"); } conn.close(); return rei;
}} |
|
|