Secure Your Spring Boot App with Apache Shiro: Auth, Authz, and Redis
This article walks through integrating Apache Shiro into a Spring Boot project to handle authentication, authorization, session management, and caching, including custom realms, Redis-backed sessions, and cache managers, while providing detailed code examples and configuration guidance.
Introduction
Throughout an application's lifecycle, data security—especially user legitimacy and data visibility—is crucial. In micro‑service architectures, sharing sessions and caching authentication/authorization data under high concurrency becomes a challenge, which Apache Shiro addresses with a simple yet powerful API.
What Is Shiro?
Apache Shiro™ is a robust, easy‑to‑use Java security framework that supports authentication, authorization, cryptography, and session management. Its API is straightforward, allowing any application—from tiny mobile apps to large enterprise systems—to become secure without requiring Spring.
Shiro vs. Spring Security
Shiro is lightweight and can operate independently of Spring, offering coarser granularity, while Spring Security is more complex, tightly coupled to Spring, and provides finer‑grained controls.
Core Components
Subject
The Subject represents the current user (or any interacting entity such as a bot). All interactions are delegated to the SecurityManager.
SecurityManager
The SecurityManager is the heart of Shiro, managing all Subjects and coordinating with other components, similar to Spring MVC’s DispatcherServlet.
Realm
Realms are data sources for authentication and authorization information. Shiro queries a Realm to verify credentials and retrieve roles/permissions.
SessionManager & SessionDAO
These manage the lifecycle of sessions, allowing custom storage (e.g., Redis) for distributed environments.
CacheManager
Handles caching of security data such as permissions to improve performance.
Cryptography
Provides utilities for password hashing and encryption.
Setup Overview
Most developers use Spring Boot, and Shiro offers a starter for easy integration. The typical dependencies include Spring Boot, JPA, MySQL, Redis, Lombok, Guava, and Shiro.
After adding the starter, configure application.yml (see image) to enable Shiro filters and session settings.
Authentication
User Entity
@Data
@Entity
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(unique = true)
private String username;
private String password;
private String salt;
}User Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findUserByUsername(String username);
}Login Controller
@GetMapping("/login")
public void login(String username, String password) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);
Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);
}Custom Realm (Authentication)
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
User user = userRepository.findUserByUsername(username);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
return info;
}Key questions: how Shiro is applied, how the controller reaches the custom realm, and the purpose of overriding doGetAuthenticationInfo (to provide authentication data from the application’s data source).
Authorization
Authorization verifies what actions a user can perform. Shiro provides annotations such as @RequiresPermissions, @RequiresRoles, @RequiresAuthentication, etc.
Role Entity & Repository
@Data
@Entity
public class Role {
@Id
@GeneratedValue(strategy = AUTO)
private Long id;
@Column(unique = true)
private String roleCode;
private String roleName;
} @Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
@Query("select roleId from UserRoleRel ur where ur.userId = ?1")
List<Long> findUserRole(Long userId);
List<Role> findByIdIn(List<Long> ids);
}Permission Entity & Repository
@Data
@Entity
public class Permission {
@Id
@GeneratedValue(strategy = AUTO)
private Long id;
@Column(unique = true)
private String permCode;
private String permName;
} @Repository
public interface PermissionRepository extends JpaRepository<Permission, Long> {
@Query("select permId from RolePermRel pr where pr.roleId in ?1")
List<Long> findRolePerm(List<Long> roleIds);
List<Permission> findByIdIn(List<Long> ids);
}Custom Realm (Authorization)
The realm’s doGetAuthorizationInfo method assembles the user’s roles and permissions from the repositories, enabling Shiro’s annotation‑driven checks.
Session Management
Shiro’s session concepts mirror traditional web sessions but can be customized. Important configuration keys (e.g., shiro.sessionManager.cookie.name, shiro.loginUrl) are listed in the original table.
Redis Integration
To store sessions in Redis for distributed systems, define a RedisConfig bean and a custom RedisSessionDao that reads/writes session data via RedisTemplate.
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisTemplate<String, Object> stringObjectRedisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}Session beans are then wired to use the custom DAO:
@Bean(name = "customerWebSessionManager")
public CustomerWebSessionManager customerWebSessionManager() {
CustomerWebSessionManager manager = new CustomerWebSessionManager();
manager.setSessionDAO(redisSessionDao());
return manager;
}
@Bean(name = "securityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(CustomRealm customRealm) {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(customRealm);
manager.setSessionManager(customerWebSessionManager());
manager.setCacheManager(redisCacheManagers());
return manager;
}Cache Management
To avoid frequent database hits for permission data, Shiro’s cache can be backed by Redis. A RedisCache implementation stores entries with a shiro-cache: prefix, and a RedisCacheManager returns this cache instance.
@Component
public class RedisCache<K, V> implements Cache<K, V> {
public static final String SHIRO_PREFIX = "shiro-cache:";
@Resource
private RedisTemplate<String, Object> stringObjectRedisTemplate;
private String getKey(K key) {
return (key instanceof String) ? SHIRO_PREFIX + key : key.toString();
}
@Override
public V get(K k) {
return (V) stringObjectRedisTemplate.opsForValue().get(getKey(k));
}
@Override
public V put(K k, V v) {
stringObjectRedisTemplate.opsForValue().set(getKey(k), v);
stringObjectRedisTemplate.expire(getKey(k), 100, java.util.concurrent.TimeUnit.SECONDS);
return v;
}
@Override
public V remove(K k) {
V v = get(k);
stringObjectRedisTemplate.delete(getKey(k));
return v;
}
// size, keys, values, clear are left as no‑ops for simplicity
@Override public void clear() {}
@Override public int size() { return 0; }
@Override public java.util.Set<K> keys() { return null; }
@Override public java.util.Collection<V> values() { return null; }
}
public class RedisCacheManager implements CacheManager {
@Resource
private RedisCache redisCache;
@Override
public <K, V> Cache<K, V> getCache(String name) {
return redisCache;
}
}Conclusion
The guide outlines the full process of integrating Shiro with Spring Boot, customizing authentication and authorization via realms, and enhancing scalability with Redis‑backed sessions and caches. Readers are encouraged to explore the demo code and the official Shiro documentation for deeper understanding.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
