Apache Shiro is a lightweight Java security framework providing authentication, authorization, session management, and cryptography. It is simpler than Spring Security and works outside the Spring ecosystem.

Core Concepts

Concept Description
Subject Current user (thread-bound)
SecurityManager Central coordinator
Realm Bridge to user data (DB, LDAP)
Session User session management
Filter Request-level security

Maven Dependency

  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.13.0</version>
</dependency>
  

INI Configuration

shiro.ini:

  [main]
authc = org.apache.shiro.web.filter.authc.FormAuthenticationFilter
roles = org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

[users]
admin = secret, admin
alice = password, user

[roles]
admin = *
user = order:read, order:create

[urls]
/login = authc
/logout = logout
/admin/** = roles[admin]
/api/** = authc
  

Programmatic Authentication

  Subject currentUser = SecurityUtils.getSubject();

if (!currentUser.isAuthenticated()) {
    UsernamePasswordToken token = new UsernamePasswordToken("alice", "password");
    token.setRememberMe(true);
    try {
        currentUser.login(token);
    } catch (UnknownAccountException | IncorrectCredentialsException e) {
        // handle failed login
    }
}

// Check permissions
if (currentUser.isPermitted("order:create")) {
    createOrder();
}

currentUser.logout();
  

Custom Realm

  public class DatabaseRealm extends AuthorizingRealm {
    private final UserRepository userRepository;

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        String email = (String) token.getPrincipal();
        User user = userRepository.findByEmail(email)
            .orElseThrow(() -> new UnknownAccountException("Unknown user: " + email));
        return new SimpleAuthenticationInfo(email, user.getPasswordHash(), getName());
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String email = (String) principals.getPrimaryPrincipal();
        User user = userRepository.findByEmail(email).orElseThrow();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(user.getRoles());
        info.setStringPermissions(user.getPermissions());
        return info;
    }
}
  

Spring Boot Integration

  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.13.0</version>
</dependency>
  
  @Bean
public Realm realm() {
    return new DatabaseRealm(userRepository);
}
  

Shiro vs Spring Security

Feature Shiro Spring Security
Complexity Lower Higher
Spring integration Good Native
OAuth2/OIDC Limited Full support
Ecosystem Smaller Large
Best for Simple apps, non-Spring Enterprise Spring apps

Best Practices

  • Use BCrypt or similar for password hashing in custom Realms
  • Keep Realm logic focused on data access — no business rules
  • Use permission strings (resource:action) for fine-grained control
  • Prefer Spring Security for new Spring Boot projects with OAuth2 needs
  • Enable session timeout and concurrent session control in production