用户类
优化用户主要是要解决用户的连接量。已经对用户的访问速度和吞吐量。
预初始化
在前面的带面中提出来了用户的预初始化。这里就不在贴出来了。下面将redis用户库连接池处理贴出来UserJedisPoolManager
public class UserJedisPoolManager extends BasicModule{ private static final Logger log = LoggerFactory.getLogger(UserJedisPoolManager.class); private static final String OF_ALL_USER = "select username, encryptedPassword, name, email, moblie, creationDate, modificationDate from ofuser"; private static final String OF_USER_VCARD = "select username, vcard from ofvcard"; private static final String OF_PRESENCE = "select username, offlinePresence, offlineDate from ofPresence"; //private static final String REDIS_USER = "REDIS_USER"; private static final Integer timeout = 1000*10; private static final int maxActive = 5000 * 10; private static final int maxIdle = 50; private static final long maxWait = (1000 * 100); private static JedisPool pool; private static XMPPServer loaclserver; private static JedisPoolConfig configs; public UserJedisPoolManager() { super("User redis manager"); } private static JedisPoolConfig createConfig() { configs = new JedisPoolConfig(); configs.setMaxActive(maxActive); configs.setMaxIdle(maxIdle); configs.setMaxWait(maxWait); configs.setTestOnBorrow(false); return configs; } private void createJedisPool() { RedisConfig redisConfig = loaclserver.getJedisConfDao().getRedisConfig("REDIS_USER"); if (redisConfig != null) { + " ,auto:" + redisConfig.getAuto()); System.out.println(redisConfig.getAuto() .equals("") ); pool = new JedisPool(createConfig(), redisConfig.getIp(), Integer.valueOf(redisConfig.getPort().trim()), timeout, redisConfig.getAuto().equals("") ? null : redisConfig.getAuto()); Jedis jedis = pool.getResource(); jedis.select(0); if(!jedis.exists("OFUSER:admin")) { DefaultAuthProvider dup = new DefaultAuthProvider(); try { String password = dup.getPassword("admin"); password = AuthFactory.encryptPassword(password); Map<String, String> map = new HashMap<String, String>(); map.put("NAME", "admin"); map.put("PASSWORD", password); map.put("CREATIONDATE", "0"); map.put("MODIFICATIONDATE", "0"); jedis.hmset("OFUSER:admin", map); } catch (UserNotFoundException e) { e.printStackTrace(); }finally{ pool.returnResource(jedis); } } } } private void poolInit() { createJedisPool(); } public Jedis getJedis() { if (pool == null) { poolInit(); } Jedis jedis = pool.getResource(); jedis.select(0); return jedis; } public void returnRes(Jedis jedis) { pool.returnResource(jedis); } @Override public void initialize(XMPPServer server) { super.initialize(server); loaclserver = server; poolInit(); log.info("UserManager By Redis: start init...."); } public Collection<User> getAllUser() { Collection<User> users = new ArrayList<User>(); PreparedStatement pstmt = null; Connection con = null; ResultSet rs = null; try { con = (Connection) DbConnectionManager.getConnection(); pstmt = con.prepareStatement(OF_ALL_USER); rs = pstmt.executeQuery(); while(rs.next()) { User user = new User(); user.setUsername(rs.getString(1)); user.setPassword(rs.getString(2)); user.setName(rs.getString(3)); user.setEmail(rs.getString(4)); user.setMoblie(rs.getString(5)); user.setCreationDate(rs.getString(6)); user.setModificationDate(rs.getString(7)); users.add(user); } }catch (Exception e) { log.info( e.getMessage()); e.printStackTrace(); } finally { DbConnectionManager.closeConnection(pstmt, con); } return users; } public Collection<UserVcard> getUserVcard() { Collection<UserVcard> userVcards = new ArrayList<UserVcard>(); PreparedStatement pstmt = null; Connection con = null; ResultSet rs = null; try { con = (Connection) DbConnectionManager.getConnection(); pstmt = con.prepareStatement(OF_USER_VCARD); rs = pstmt.executeQuery(); while(rs.next()) { UserVcard user = new UserVcard(); user.setUsername(rs.getString(1)); user.setVcard(rs.getString(2)); userVcards.add(user); } }catch (Exception e) { log.info( e.getMessage()); e.printStackTrace(); } finally { DbConnectionManager.closeConnection(pstmt, con); } return userVcards; } public Collection<Presence> getPresences() { ...... } }
在上面createJedisPool方法中预置了管理员的账号。这是因为我们需要修改openfire的用户认证dao。也就是说web控制台的管理员。在登陆web页面的时候,我们认证也是先走redis验证的。
用户认证
用户认证,首先需要重新实现AuthProvider。Openfire当中默认使用的是DefaultAuthProvider来操作数据层。当然他也提供了其他的方式实现接口,比如:HybridAuthProvider、JDBCAuthProvider、NativeAuthProvider、POP3AuthProvider等。
写完AuthProvider的Redis实现后,接下来需要基于Redis的用户DAO。
下面是两个类的源码清单:
RedisAuthProvider
public class RedisAuthProvider implements AuthProvider{ private static final Logger log = LoggerFactory.getLogger(RedisAuthProvider.class); private static HmThreadPool threadPool = new HmThreadPool(3); ...... @Override public void authenticate(String username, String password) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException { ...... } @Override public void authenticate(String username, String token, String digest) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException { ...... } @Override public String getPassword(String username) throws UserNotFoundException, UnsupportedOperationException { Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis(); try { String pw = jedis.hmget("OFUSER:" + username, "PASSWORD").get(0); if (pw == null) { String userid = jedis.get("MOBILE:" + username); pw = jedis.hmget("OFUSER:" + userid, "PASSWORD").get(0); } return AuthFactory.decryptPassword(pw); } finally { XMPPServer.getInstance().getUserJedis().returnRes(jedis); } } @Override public void setPassword(String username, String password) throws UserNotFoundException, UnsupportedOperationException { Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis(); try { password = AuthFactory.encryptPassword(password); jedis.hset("OFUSER:" + username, "PASSWORD", password); } finally { XMPPServer.getInstance().getUserJedis().returnRes(jedis); } threadPool.execute(createTask(XMPPServer.getInstance().getJedisConfDao().getAuthProvider(), username, password)); } @Override public boolean supportsPasswordRetrieval() { // TODO Auto-generated method stub return true; } private static final String UPDATE_PASSWORD = "UPDATE ofUser SET encryptedPassword=? WHERE username=?"; private Runnable createTask(final AuthProvider edp, final String username, final String password) { return new Runnable() { public void run() { try { //edp.setPassword(username, password); Connection con = null; PreparedStatement pstmt = null; try { con = DbConnectionManager.getConnection(); pstmt = con.prepareStatement(UPDATE_PASSWORD); if (password == null) { pstmt.setNull(1, Types.VARCHAR); } else { pstmt.setString(1, password); } pstmt.setString(2, username); pstmt.executeUpdate(); } catch (SQLException sqle) { throw new UserNotFoundException(sqle); } finally { DbConnectionManager.closeConnection(pstmt, con); } } catch (UserNotFoundException e) { log.info("UserNotFoundException: " + username); } } }; } }
用户认证写完后,要记得修改系统属性表:ofProperty
provider.auth.className |
org.jivesoftware.util.redis.expand.RedisAuthProvider |
RedisUserProvider:
public class RedisUserProvider implements UserProvider{ ...... public User loadUser(String username) throws UserNotFoundException { if(username.contains("@")) { if (!XMPPServer.getInstance().isLocal(new JID(username))) { throw new UserNotFoundException("Cannot load user of remote server: " + username); } username = username.substring(0,username.lastIndexOf("@")); } Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis(); try { Map<String, String> map = jedis.hgetAll("OFUSER:" + username); String usernames = username; if (map.isEmpty()) { String userid = jedis.get("OFUSER:" + username); map = jedis.hgetAll("OFUSER:" + userid); if (map.isEmpty()) { return XMPPServer.getInstance().getJedisConfDao().getUserProvider().loadUser(username); } usernames = userid; } String name = map.get("NAME"); String email = map.get("EMAIL"); String mobile = map.get("MOBILE"); String creationDate = map.get("CREATIONDATE"); String modificationDate = map.get("MODIFICATIONDATE"); User user = new User(usernames, name, email, mobile, new Date(Long.parseLong(creationDate.equals("0")||creationDate.equals("") ? StringUtils.dateToMillis(new Date()) : creationDate)), new Date(Long.parseLong(modificationDate.equals("0")||modificationDate.equals("") ? StringUtils.dateToMillis(new Date()) : modificationDate))); return user; } finally { XMPPServer.getInstance().getUserJedis().returnRes(jedis); } } public User createUser(String username, String password, String name, String email) throws UserAlreadyExistsException { return createUser(username, password, name, email, null); } public User createUser(String username, String password, String name, String email, String moblie) throws UserAlreadyExistsException{ try { loadUser(username); // The user already exists since no exception, so: throw new UserAlreadyExistsException("Username " + username + " already exists"); } catch (UserNotFoundException unfe) { Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis(); Map<String, String> hash = new HashMap<String, String>(); password = AuthFactory.encryptPassword(password); hash.put("PASSWORD", password); if (name != null && !"".equals(name)) hash.put("NAME", name); if (email != null && !"".equals(email)) hash.put("EMAIL", email); if (moblie != null && !"".equals(moblie)) hash.put("MOBILE", moblie); Date now = new Date(); hash.put("CREATIONDATE", StringUtils.dateToMillis(now)); hash.put("MODIFICATIONDATE", StringUtils.dateToMillis(now)); try { jedis.hmset("OFUSER:" + username, hash); } finally { XMPPServer.getInstance().getUserJedis().returnRes(jedis); } threadPool.execute(createTaskAddUser(username, null, password, name, email, moblie)); return new User(username, name, email, moblie, now, now); } } private Runnable createTaskAddUser(final String username, final String password, final String encryptedPassword, final String name, final String email, final String moblie) { return new Runnable() { public void run () { ..... } }; } public void deleteUser(String username) { ...... } public int getUserCount() { int count = 0; Connection con = null; PreparedStatement pstmt = null; ResultSet rs = null; try { con = DbConnectionManager.getConnection(); pstmt = con.prepareStatement(USER_COUNT); rs = pstmt.executeQuery(); if (rs.next()) { count = rs.getInt(1); } } catch (SQLException e) { Log.error(e.getMessage(), e); } finally { DbConnectionManager.closeConnection(rs, pstmt, con); } return count; } public Collection<User> getUsers() { Collection<String> usernames = getUsernames(0, Integer.MAX_VALUE); return new UserCollection(usernames.toArray(new String[usernames.size()])); } public Collection<String> getUsernames() { return getUsernames(0, Integer.MAX_VALUE); } private Collection<String> getUsernames(int startIndex, int numResults) { ...... } public Collection<User> getUsers(int startIndex, int numResults) { Collection<String> usernames = getUsernames(startIndex, numResults); return new UserCollection(usernames.toArray(new String[usernames.size()])); } public void setName(String username, String name) throws UserNotFoundException { ...... } public void setEmail(String username, String email) throws UserNotFoundException { ...... } public void setCreationDate(String username, Date creationDate) throws UserNotFoundException { ...... } public void setModificationDate(String username, Date modificationDate) throws UserNotFoundException { ...... } public Set<String> getSearchFields() throws UnsupportedOperationException { return new LinkedHashSet<String>(Arrays.asList("Username", "Name", "Email")); } public Collection<User> findUsers(Set<String> fields, String query) throws UnsupportedOperationException { return findUsers(fields, query, 0, 100); } public Collection<User> findUsers(Set<String> fields, String query, int startIndex, int numResults) throws UnsupportedOperationException { ...... } /** * Make sure that Log.isDebugEnabled()==true before calling this method. * Twenty elements will be logged in every log line, so for 81-100 elements * five log lines will be generated * @param listElements a list of Strings which will be logged */ private void LogResults(List<String> listElements) { ...... } @Override public void setMoblie(String username, String moblie) throws UserNotFoundException { ...... } }
注意:这里有个moblie字段。在原来openfire用户认证表里面是没有这个字段的。这里是本人新加的字段。方便手机登陆。看各自的页面场景啦。
时间: 2024-10-21 03:30:33