Java平台提供的认证与授权服务(Java Authentication and Authorization Service (JAAS)),能够控制代码对敏感或关键资源的访问,例如文件系统,网络服务,系统属性访问等,加强代码的安全性。主要包含认证与授权两部分,认证的目的在于可靠安全地确定当前是谁在执行代码,代码可以是一个应用,applet,bean,servlet;授权的目的在于确定了当前执行代码的用户有什么权限,资源是否可以进行访问。虽然JAAS表面上分为了两大部分,而实际上两者是密不可分的,下面看一段代码:
public class App { public static void main(String[] args) { System.out.println(System.getProperty("java.home")); } }
public class App { public static void main(String[] args) { //安装安全管理器 System.setSecurityManager(new SecurityManager()); System.out.println(System.getProperty("java.home")); } }
grant { permission java.util.PropertyPermission "java.home", "read"; };
package com.xtayfjpk.security.jaas.demo; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; public class App { public static void main(String[] args) { System.setProperty("java.security.auth.login.config", "demo.config"); System.setProperty("java.security.policy", "demo.policy"); System.setSecurityManager(new SecurityManager()); try { //创建登录上下文 LoginContext context = new LoginContext("demo", new DemoCallbackHander()); //进行登录,登录不成功则系统退出 context.login(); } catch (LoginException le) { System.err.println("Cannot create LoginContext. " + le.getMessage()); System.exit(-1); } catch (SecurityException se) { System.err.println("Cannot create LoginContext. " + se.getMessage()); System.exit(-1); } //访问资源 System.out.println(System.getProperty("java.home")); } }
package com.xtayfjpk.security.jaas.demo; import java.io.IOException; import java.security.Principal; import java.util.Iterator; import java.util.Map; 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.FailedLoginException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; public class DemoLoginModule implements LoginModule { private Subject subject; private CallbackHandler callbackHandler; private boolean success = false; private String user; private String password; @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { this.subject = subject; this.callbackHandler = callbackHandler; } @Override public boolean login() throws LoginException { NameCallback nameCallback = new NameCallback("请输入用户名"); PasswordCallback passwordCallback = new PasswordCallback("请输入密码", false); Callback[] callbacks = new Callback[]{nameCallback, passwordCallback}; try { //执行回调,回调过程中获取用户名与密码 callbackHandler.handle(callbacks); //得到用户名与密码 user = nameCallback.getName(); password = new String(passwordCallback.getPassword()); } catch (IOException | UnsupportedCallbackException e) { success = false; throw new FailedLoginException("用户名或密码获取失败"); } //为简单起见认证条件写死 if(user.length()>3 && password.length()>3) { success = true;//认证成功 } return true; } @Override public boolean commit() throws LoginException { if(!success) { return false; } else { //如果认证成功则得subject中添加一个Principal对象 //这样某身份用户就认证通过并登录了该应用,即表明了谁在执行该程序 this.subject.getPrincipals().add(new DemoPrincipal(user)); return true; } } @Override public boolean abort() throws LoginException { logout(); return true; } @Override public boolean logout() throws LoginException { //退出时将相应的Principal对象从subject中移除 Iterator<Principal> iter = subject.getPrincipals().iterator(); while(iter.hasNext()) { Principal principal = iter.next(); if(principal instanceof DemoPrincipal) { if(principal.getName().equals(user)) { iter.remove(); break; } } } return true; } }
package com.xtayfjpk.security.jaas.demo; import java.io.IOException; 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; public class DemoCallbackHander implements CallbackHandler { @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { NameCallback nameCallback = (NameCallback) callbacks[0]; PasswordCallback passwordCallback = (PasswordCallback) callbacks[1]; //设置用户名与密码 nameCallback.setName(getUserFromSomeWhere()); passwordCallback.setPassword(getPasswordFromSomeWhere().toCharArray()); } //为简单起见用户名与密码写死直接返回,真实情况可以由用户输入等具体获取 public String getUserFromSomeWhere() { return "zhangsan"; } public String getPasswordFromSomeWhere() { return "zhangsan"; } }
package com.xtayfjpk.security.jaas.demo; import java.security.Principal; public class DemoPrincipal implements Principal { private String name; public DemoPrincipal(String name) { this.name = name; } @Override public String getName() { return this.name; } }
demo { com.xtayfjpk.security.jaas.demo.DemoLoginModule required debug=true; };
grant { permission javax.security.auth.AuthPermission "createLoginContext.demo"; permission javax.security.auth.AuthPermission "modifyPrincipals"; permission java.util.PropertyPermission "java.home", "read"; };
grant principal com.xtayfjpk.security.jaas.demo.DemoPrincipal "zhangsan"{ permission java.util.PropertyPermission "java.home", "read"; }; grant { permission javax.security.auth.AuthPermission "createLoginContext.demo"; permission javax.security.auth.AuthPermission "modifyPrincipals"; permission javax.security.auth.AuthPermission "doAsPrivileged"; };
Subject subject = context.getSubject(); //该方法调用需要"doAsPrivileged"权限 Subject.doAsPrivileged(subject, new PrivilegedAction<Object>() { @Override public Object run() { System.out.println(System.getProperty("java.home")); return null; } }, null);