Java认证和授权服务 JAAS 之 认证

LoginModule

    它是认证服务器端的实现,用于验证客户端的信息,实现者实现 javax.security.auth.spi.LoginModule 接口的 login、commit、abort、logout 方法来完成用户的登录和登出操作,示例代码:


package jaas;import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import java.security.Principal;
import java.util.Map;public class MyLoginModule implements LoginModule {// username and passwordprivate String username;private char[] password;// the authentication statusprivate boolean userPwdSucceeded = false;private boolean commitSucceeded = false;// user's Principalprivate Principal userPrincipal;// initial stateprivate Subject subject;private CallbackHandler callbackHandler;/*** Initialize this LoginModule.*/public void initialize(Subject subject,CallbackHandler callbackHandler,Map sharedState,Map options) {this.subject = subject;this.callbackHandler = callbackHandler;}/*** Authenticate the user by prompting for a user name and password.*/public boolean login() throws LoginException {// prompt for a user name and passwordif (callbackHandler == null)throw new LoginException("Error: no CallbackHandler available " +"to garner authentication information from the user");Callback[] callbacks = new Callback[4];callbacks[0] = new NameCallback("user name");callbacks[1] = new PasswordCallback("password", false);callbacks[2] = new TextOutputCallback(TextOutputCallback.INFORMATION, "hello, just a msg!");callbacks[3] = new TextOutputCallback(TextOutputCallback.WARNING, "just warn you!");try {callbackHandler.handle(callbacks);NameCallback nameCallback = (NameCallback) callbacks[0];PasswordCallback passwordCallback = (PasswordCallback) callbacks[1];username = nameCallback.getName();char[] tmpPassword = passwordCallback.getPassword();passwordCallback.clearPassword();// clean password in memory spaceif (tmpPassword == null) {tmpPassword = new char[0];// treat a NULL password as an empty password}password = new char[tmpPassword.length];System.arraycopy(tmpPassword, 0, password, 0, tmpPassword.length);} catch (Exception e) {e.printStackTrace();}// verify the username/passwordboolean usernameCorrect = false;if (username.equals("user")) usernameCorrect = true;if (usernameCorrect &&password.length == 3 &&password[0] == 'p' &&password[1] == 'w' &&password[2] == 'd') {userPwdSucceeded = true;} else {userPwdSucceeded = false;cleanUserAndPwdData();if (!usernameCorrect) {throw new FailedLoginException("User Name Incorrect");} else {throw new FailedLoginException("Password Incorrect");}}return userPwdSucceeded;}public boolean commit() throws LoginException {if (!userPwdSucceeded) return false;// add a Principal (authenticated identity) to the SubjectuserPrincipal = new SamplePrincipal(username);subject.getPrincipals().add(userPrincipal);// in any case, clean out statecleanUserAndPwdData();return commitSucceeded = true;}public boolean abort() throws LoginException {if (!userPwdSucceeded) return false;if (commitSucceeded) {logout();} else {cleanState();}return true;}public boolean logout() throws LoginException {subject.getPrincipals().remove(userPrincipal);cleanState();userPwdSucceeded = commitSucceeded;return true;}private void cleanState() {userPwdSucceeded = false;cleanUserAndPwdData();userPrincipal = null;}private void cleanUserAndPwdData() {username = null;if (password != null) {for (int i = 0; i < password.length; i++)password[i] = ' ';password = null;}}
}


test_jaas.config 登录配置文件

/** 登录配置 **/
Sample {jaas.MyLoginModule required debug=true;
};

Principal 用户身份信息

示例代码:

package jaas;import java.security.Principal;public class SamplePrincipal implements Principal {private String name;public SamplePrincipal(String name) {this.name = name;}public String getName() {return name;}public boolean equals(Object o) {if (o == null)return false;if (this == o)return true;if (!(o instanceof SamplePrincipal))return false;SamplePrincipal that = (SamplePrincipal) o;if (this.getName().equals(that.getName()))return true;return false;}public int hashCode() {return name.hashCode();}
}


CallbackHandler 用户交互回调接口

用户代码通过该回调可传入用户名、密码 或其它信息 供 验证服务器使用,java 预置了多种回调实现:

 * @see javax.security.auth.callback.ChoiceCallback* @see javax.security.auth.callback.ConfirmationCallback* @see javax.security.auth.callback.LanguageCallback* @see javax.security.auth.callback.NameCallback* @see javax.security.auth.callback.PasswordCallback* @see javax.security.auth.callback.TextInputCallback* @see javax.security.auth.callback.TextOutputCallback
示例代码:

package jaas;import javax.security.auth.callback.*;
import java.io.IOException;public class MyCallbackHandler implements CallbackHandler {public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {for (int i = 0; i < callbacks.length; i++) {if (callbacks[i] instanceof TextOutputCallback) {// display the message according to the specified typeTextOutputCallback toc = (TextOutputCallback) callbacks[i];switch (toc.getMessageType()) {case TextOutputCallback.INFORMATION:System.out.println(toc.getMessage());break;case TextOutputCallback.ERROR:System.err.println("ERROR: " + toc.getMessage());break;case TextOutputCallback.WARNING:System.err.println("WARNING: " + toc.getMessage());break;default:throw new IOException("Unsupported message type: " + toc.getMessageType());}} else if (callbacks[i] instanceof NameCallback) {// prompt the user for a usernameNameCallback nc = (NameCallback) callbacks[i];String name = "user";// TODO 这里可以实现为从控制台允许用户输入等方式接收用户参数。。。nc.setName(name);} else if (callbacks[i] instanceof PasswordCallback) {// prompt the user for sensitive informationPasswordCallback pc = (PasswordCallback) callbacks[i];String pwd = "pwd";// TODO 这里可以实现为从控制台允许用户输入等方式接收用户参数。。。pc.setPassword(pwd.toCharArray());} else {throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");}}}
}

测试

当登录模块和用户回调实现好以后,就可以进行测试,示例代码:
package jaas;import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;public class Main {public static void main(String[] args) throws LoginException {// 配置文件中查找 Sample 名字的 LoginModule,并指定 CallbackHandlerLoginContext lc = new LoginContext("Sample", new MyCallbackHandler());try {lc.login();Subject subject = lc.getSubject();
//            System.out.println(subject);System.out.println("Authentication succeeded!");} catch (LoginException le) {System.err.println("Authentication failed:" + le.getMessage());}}
}

注意,上述的 new LoginContext("Sample", new MyCallbackHandler()); 是将 登录模块和用户回调关联起来,Sample为登录配置文件中指定的名字,java的jaas服务会通过 -D参数读取并初始化该登录模块,回调接口为用户自定义的交互对象,运行参数如下:

-Djava.security.auth.login.config=/xx/test/test_jaas.config

运行结果

由于示例代码中在 MyCallbackHandler 中硬编码指定了正确的用户名和密码,所以可以看到正确的输出:“Authentication succeeded!”

MyCallbackHandler 为自定义的交互类,可以实现为通过 web 请求中获取用户名和密码,或者从控制台 System.in  接收输入的用户名和密码等。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部