Didn't mean much by information at the time. But, after looking at the code, I suppose my concern would be with getAuthorizationInfo() of the AuthorizingRealm - if caching is enabled, it seems to me that your technique might be dangerous.
Thanks, Jared On 07/08/2011 04:21 PM, Les Hazlewood wrote: > Hi Jared, > > What do you mean exactly? What information? > > Cheers, > > Les > > On Fri, Jul 8, 2011 at 11:54 AM, Jared Bunting > <[email protected]> wrote: >> Les, >> >> I like the approach. Do you have to be concerned with the realm caching >> information though? >> >> Thanks, >> Jared >> >> On 07/08/2011 01:51 PM, Les Hazlewood wrote: >>> Here's how we do this in our own Shiro-based multi-tenant application: >>> >>> We have a TenantFilter (a Servlet Filter) that filters all incoming >>> HTTP requests (only HTTP/S communication is performed by clients, so >>> we only have to worry about the HTTP protocol). The TenantFilter >>> inspects the hostname specified in the request (e.g. >>> companyname.mysite.com). We parse out 'companyname' and perform a >>> lookup in our data store for the Tenant entity corresponding to that >>> name. >>> >>> Once the Tenant object is acquired we bind it to a ThreadLocal so it >>> is available for the duration of the request (the TenantFilter ensures >>> it is removed from the thread, even in the event of any exception to >>> ensure the thread remains 'clean' in a thread-pooled environment). >>> >>> All tenant-related query logic is handled in our DAO layer - the rest >>> of the codebase (including Shiro), never 'knows' about the Tenant >>> concept. The DAOs are the ones that inspect the Tenant ThreadLocal >>> and manipulate the query. >>> >>> For example, you might have a UserDAO that looks up a User by >>> username, and your Realm implementation would use the UserDAO to >>> acquire the User object. >>> >>> Your Realm's doGetAuthenticationInfo implementation might look >>> something like this: >>> >>> ======================== >>> UsernamePasswordToken upToken = (UsernamePasswordToken) token; >>> String username = upToken.getUsername(); >>> >>> User user = userDAO.findByUsername(username); >>> if (user == null) { >>> throw new UnknownAccountException("No account found for username >>> '" + username + "'"); >>> } else if (user.isDisabled()) { >>> throw new DisabledAccountException("The account for username '" + >>> username + "' is disabled"); >>> } else if (user.isLocked()) { >>> throw new LockedAccountException("The account for username '" + >>> username + "' is locked"); >>> } >>> >>> SimpleAccount shiroAccount = new SimpleAccount(user.getId(), >>> user.getHashedPassword(), getName()); >>> shiroAccount.setCredentialsSalt(new >>> SimpleByteSource(Base64.decode(account.getPasswordSalt()); >>> >>> return shiroAccount; >>> ======================== >>> >>> Notice how we didn't reference the tenant anywhere? >>> >>> The UserDAO implementation is the thing that inspects the Tenant >>> ThreadLocal. It's 'findByUsername' implementation can do this for >>> example (e.g. using JPA or Hibernate queries): >>> >>> User findByUsername(String username) { >>> Object[] queryParams = {username, TENANT_THREAD_LOCAL.get().getId()}; >>> return executeQuery("from User u where u.username = ? and >>> u.tenant.id = ?", queryParams); >>> } >>> >>> We consider the Tenant concept to be a more infrastructural/EIS-level >>> concern and not something that should bubble up into code much (if at >>> all). The TenantFilter and the DAOs encapsulate this logic quite >>> nicely away from the rest of the application. >>> >>> HTH! >>> >>> Best regards,
