Shiro安全框架集成与实战用法详解
Shiro常规用法详解:从集成到实战场景
Shiro作为一款轻量级安全框架,其常规用法涵盖了多种集成方式和典型应用场景。本文将深入讲解Shiro在实际项目中的标准用法,帮助开发者快速掌握核心配置和常见模式。
一、集成方式
1. 独立应用集成(非Spring环境)
在非Spring应用中集成Shiro需要手动创建SecurityManager实例:
// 创建SecurityManager并绑定到静态工具类
DefaultSecurityManager securityManager = new DefaultSecurityManager();
SecurityUtils.setSecurityManager(securityManager);
// 配置Realm
IniRealm realm = new IniRealm("classpath:shiro.ini");
securityManager.setRealm(realm);
实践建议:适合传统Java SE应用或遗留系统改造,但需要自行管理组件生命周期。
2. Spring/Spring Boot整合
Spring环境下通过ShiroFilterFactoryBean
实现集成:
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
// 配置拦截规则
Map<String, String> filterChain = new LinkedHashMap<>();
filterChain.put("/login", "anon");
filterChain.put("/admin/**", "authc, roles[admin]");
filterChain.put("/**", "authc");
factoryBean.setFilterChainDefinitionMap(filterChain);
return factoryBean;
}
Spring Boot自动配置示例:
# application.properties
shiro.enabled=true
shiro.loginUrl=/login
shiro.successUrl=/home
shiro.unauthorizedUrl=/403
二、配置示例
1. INI基础配置
# shiro.ini
[main]
# 定义Realm
myRealm = com.example.MyRealm
securityManager.realms = $myRealm
# 加密配置
credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
credentialsMatcher.storedCredentialsHexEncoded = false
myRealm.credentialsMatcher = $credentialsMatcher
[urls]
/login = anon
/logout = logout
/account/** = user
2. 注解驱动安全控制
@Controller
public class AdminController {
@RequiresRoles("admin")
@GetMapping("/admin/dashboard")
public String adminDashboard() {
return "dashboard";
}
@RequiresPermissions("user:delete")
@DeleteMapping("/user/{id}")
public void deleteUser(@PathVariable Long id) {
// 删除用户逻辑
}
}
实践建议:注解方式适合方法级细粒度控制,但要注意AOP代理的生效条件。
三、常见场景实现
1. 登录流程定制
public class CustomFormFilter extends FormAuthenticationFilter {
@Override
protected boolean onLoginSuccess(AuthenticationToken token,
Subject subject, ServletRequest request,
ServletResponse response) throws Exception {
// 登录成功后记录日志
logLogin((UsernamePasswordToken)token);
return super.onLoginSuccess(token, subject, request, response);
}
@Override
protected boolean onLoginFailure(AuthenticationToken token,
AuthenticationException e, ServletRequest request,
ServletResponse response) {
// 登录失败处理逻辑
return super.onLoginFailure(token, e, request, response);
}
}
2. 动态URL权限控制
// 动态从数据库加载权限规则
@Bean
public FilterChainDefinitionMap dynamicFilterChain() {
return new PathMatchingFilterChainDefinition() {
@Override
public void addPathDefinitions(String path, String definition) {
// 从数据库查询path对应的权限规则
List<PermissionRule> rules = permissionService.getRulesByPath(path);
String chainDefinition = buildChainDefinition(rules);
super.addPathDefinitions(path, chainDefinition);
}
};
}
3. 自定义Realm实现
public class JdbcRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
User user = userService.findByUsername(upToken.getUsername());
if (user == null) {
throw new UnknownAccountException("用户不存在");
}
return new SimpleAuthenticationInfo(
user.getUsername(),
user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),
getName()
);
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
Set<String> roles = userService.findRolesByUsername(username);
Set<String> permissions = userService.findPermissionsByUsername(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roles);
info.setStringPermissions(permissions);
return info;
}
}
四、扩展点实践
1. 自定义JWT Token
public class JWTToken implements AuthenticationToken {
private String token;
public JWTToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return JWTUtil.parseUsername(token);
}
@Override
public Object getCredentials() {
return token;
}
}
// 配套的Realm
public class JWTRealm extends AuthenticatingRealm {
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JWTToken;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
// JWT验证逻辑
}
}
2. Redis缓存集成
@Bean
public CacheManager cacheManager(RedisTemplate<String, Object> redisTemplate) {
return new RedisCacheManager(redisTemplate) {
@Override
protected long getExpireSeconds() {
return 1800; // 30分钟过期
}
};
}
五、最佳实践总结
配置原则:
- 生产环境避免使用INI配置,推荐数据库存储动态规则
- 权限规则应遵循"最严格匹配优先"原则
- 性能优化:
安全建议:
- 重要操作应结合
@RequiresAuthentication
和@RequiresPermissions
双重验证 - 密码加密必须使用加盐哈希(如SHA-256 +随机盐值)
- 重要操作应结合
通过以上常规用法的系统实践,可以构建出既安全又灵活的应用权限体系。建议根据实际需求选择合适的集成方式和扩展点,避免过度设计。
评论已关闭