Servlet
SecurityCollection securityCollection = new SecurityCollection(); securityCollection.addPattern("/"); securityCollection.addMethod("GET"); SecurityConstraint constraint = new SecurityConstraint(); constraint.addCollection(securityCollection); constraint.addAuthRole("manager"); LoginConfig loginConfig = new LoginConfig(); loginConfig.setRealmName("Realm"); Realm realm = new SimpleRealm(); context.setRealm(realm); context.addConstraint(constraint); context.setLoginConfig(loginConfig);
我們看第一行,建立了一個securityCollection隨心,之後addPattern()就是設定需要安全限制的url,之後的addMethod不多解釋了- -GET,POST沒啥說的。之後的一段就是把secuityCollection交給constraint,之後設定只有Manager這個角色才能訪問。最後與container進行關聯。
private void createUserDatabase() { User user1 = new User("Victory", "test"); user1.addRole("manager"); user1.addRole("programmer"); User user2 = new User("Mrc", "Chri"); user2.addRole("programmer"); users.add(user1); users.add(user2); } class User { public User(String username, String password) { this.username = username; this.password = password; } public String username; public ArrayList roles = new ArrayList(); public String password; public void addRole(String role) { roles.add(role); } public ArrayList getRoles() { return roles; } }
我們會發現,在我們的realm的預設構造器中調用了createUserDatabase()之後,這個方法建立了一個使用者,使用了user這個內部類。這個realm全部的代碼我就不貼了- -這個去源碼看就妥了。
同時,我們知道這個authenticator也是一個valve,所以我們自然而然的想到了pipeline,之後很自然的想到,它應該寫在ContextConfig中。添加的代碼如下
private synchronized void authenticatorConfig() { // Does this Context require an Authenticator? SecurityConstraint constraints[] = context.findConstraints(); if ((constraints == null) || (constraints.length == 0)) return; LoginConfig loginConfig = context.getLoginConfig(); if (loginConfig == null) { loginConfig = new LoginConfig("NONE", null, null, null); context.setLoginConfig(loginConfig); } // Has an authenticator been configured already? Pipeline pipeline = ((StandardContext) context).getPipeline(); if (pipeline != null) { Valve basic = pipeline.getBasic(); if ((basic != null) && (basic instanceof Authenticator)) return; Valve valves[] = pipeline.getValves(); for (int i = 0; i < valves.length; i++) { if (valves[i] instanceof Authenticator) return; } } else { // no Pipeline, cannot install authenticator valve return; } // Has a Realm been configured for us to authenticate against? if (context.getRealm() == null) { return; } // Identify the class name of the Valve we should configure String authenticatorName = "org.apache.catalina.authenticator.BasicAuthenticator"; // Instantiate and install an Authenticator of the requested class Valve authenticator = null; try { Class authenticatorClass = Class.forName(authenticatorName); authenticator = (Valve) authenticatorClass.newInstance(); ((StandardContext) context).addValve(authenticator); System.out.println("Added authenticator valve to Context"); } catch (Throwable t) { } }
當然別忘了在lifecycleEvent這個方法中調用它。
另外的一種擷取登入賬戶資料的方法是通過xml讀取。代碼如下,只要把bootstrap更改一下就行了,之後添加一個SimpleUserDatabaseRealm類就可以了。先看SimpleUserDatabaseRealm的代碼
public class SimpleUserDatabaseRealm extends RealmBase { protected UserDatabase database = null; protected static final String name = "SimpleUserDatabaseRealm"; protected String resourceName = "UserDatabase"; public Principal authenticate(String username, String credentials) { // 檢測這個使用者名稱的使用者是否存在 User user = database.findUser(username); if (user == null) { return (null); } boolean validated = false; if (hasMessageDigest()) { validated = (digest(credentials).equalsIgnoreCase(user.getPassword())); } else { validated = (digest(credentials).equals(user.getPassword())); } if (!validated) { return null; } ArrayList combined = new ArrayList(); Iterator roles = user.getRoles(); while (roles.hasNext()) { Role role = (Role) roles.next(); String rolename = role.getRolename(); if (!combined.contains(rolename)) { combined.add(rolename); } } Iterator groups = user.getGroups(); while (groups.hasNext()) { Group group = (Group) groups.next(); roles = group.getRoles(); while (roles.hasNext()) { Role role = (Role) roles.next(); String rolename = role.getRolename(); if (!combined.contains(rolename)) { combined.add(rolename); } } } return (new GenericPrincipal(this, user.getUsername(), user.getPassword(), combined)); } protected Principal getPrincipal(String username) { return (null); } protected String getPassword(String username) { return null; } protected String getName() { return this.name; } public void createDatabase(String path) { database = new MemoryUserDatabase(name); ((MemoryUserDatabase) database).setPathname(path); try { database.open(); } catch (Exception e) { } }}
Bootstrap。
SecurityConstraint constraint = new SecurityConstraint(); constraint.addCollection(securityCollection); constraint.addAuthRole("manager"); LoginConfig loginConfig = new LoginConfig(); loginConfig.setRealmName("Simple User Database Realm"); // add realm Realm realm = new SimpleUserDatabaseRealm(); ((SimpleUserDatabaseRealm) realm).createDatabase("conf/tomcat-users.xml"); context.setRealm(realm); context.addConstraint(constraint); context.setLoginConfig(loginConfig);
這個相信不用我多說,看看代碼發現時訪問conf/tomcat-users.xml這個檔案擷取帳號,從而來驗證的。
xml的檔案內容如下
<?xml version='1.0' encoding='utf-8'?><tomcat-users> <role rolename="tomcat"/> <role rolename="programmer"/> <role rolename="manager"/> <role rolename="admin"/> <user username="tomcat" password="tomcat" roles="tomcat"/> <user username="victory" password="tomcat" roles="programmer"/> <user username="both" password="tomcat" roles="tomcat,programmer"/> <user username="admin" password="password" roles="admin,manager"/></tomcat-users>