Apache Shiro

1. 整体架构概览

2. 核心概念详解

Subject(主体)- “用户的代理人”

简单理解: Subject就是当前用户在Shiro中的”代理人”,你通过它来操作用户的认证、授权、会话等。

/**
 * Subject = 当前用户的操作界面
 * 就像银行柜台的工作人员,你告诉他要做什么,他帮你去办
 */
public interface Subject {
    // 认证相关
    void login(AuthenticationToken token);    // 登录
    void logout();                           // 登出
    boolean isAuthenticated();               // 是否已认证
    
    // 授权相关  
    boolean hasRole(String role);            // 是否有角色
    boolean isPermitted(String permission);  // 是否有权限
    
    // 会话相关
    Session getSession();                    // 获取会话
    
    // 身份相关
    Object getPrincipal();                   // 获取身份标识
    PrincipalCollection getPrincipals();     // 获取所有身份
}

// 使用示例
Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated()) {
    currentUser.login(new UsernamePasswordToken("admin", "123456"));
}

if (currentUser.hasRole("admin")) {
    // 执行管理员操作
}

if (currentUser.isPermitted("user:create")) {
    // 执行创建用户操作
}

SecurityManager(安全管理器)- “总指挥官”

简单理解: SecurityManager是Shiro的大脑,协调所有安全相关的操作。

/**
 * SecurityManager = 安全系统的总管
 * 就像公司的CEO,不直接干活,但协调各部门工作
 */
public interface SecurityManager {
    // 认证管理
    Subject login(Subject subject, AuthenticationToken token);
    void logout(Subject subject);
    
    // 会话管理  
    Session start(SessionContext context);
    
    // 创建Subject
    Subject createSubject(SubjectContext context);
}

// 配置示例
@Bean
public SecurityManager securityManager() {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setRealm(myRealm());           // 设置数据源
    securityManager.setSessionManager(sessionManager()); // 设置会话管理
    securityManager.setCacheManager(cacheManager()); // 设置缓存
    return securityManager;
}

Realm(域/领域)- “数据翻译官”

简单理解: Realm是连接Shiro和你的数据源的桥梁,告诉Shiro去哪里找用户信息。

/**
 * Realm = 数据源适配器
 * 就像翻译官,把你的数据库语言翻译给Shiro听
 */
public abstract class AuthorizingRealm extends AuthenticatingRealm {
    
    // 认证:告诉Shiro这个用户的密码是什么
    protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token);
    
    // 授权:告诉Shiro这个用户有什么权限
    protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals);
}

// 自定义Realm示例
public class MyRealm extends AuthorizingRealm {
    
    @Autowired
    private UserService userService;
    
    // 认证方法:验证用户身份
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        String username = (String) token.getPrincipal();
        
        // 从数据库查用户
        User user = userService.findByUsername(username);
        if (user == null) {
            return null; // 用户不存在
        }
        
        // 返回用户信息给Shiro
        return new SimpleAuthenticationInfo(
            user.getUsername(),    // 用户身份
            user.getPassword(),    // 密码
            getName()             // Realm名称
        );
    }
    
    // 授权方法:获取用户权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        
        // 从数据库查权限
        Set<String> roles = userService.findRolesByUsername(username);
        Set<String> permissions = userService.findPermissionsByUsername(username);
        
        // 返回权限信息给Shiro
        SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();
        authInfo.setRoles(roles);
        authInfo.setStringPermissions(permissions);
        return authInfo;
    }
}

Authenticator(认证器)- “身份验证员”

简单理解: Authenticator负责验证用户身份,决定用户是否可以登录。

/**
 * Authenticator = 身份检查员
 * 就像机场安检,检查你的身份证和机票是否匹配
 */
public interface Authenticator {
    AuthenticationInfo authenticate(AuthenticationToken authenticationToken);
}

// 默认实现:ModularRealmAuthenticator
public class ModularRealmAuthenticator extends AbstractAuthenticator {
    // 支持多个Realm的认证策略:
    // - AtLeastOneSuccessfulStrategy:至少一个成功
    // - AllSuccessfulStrategy:全部成功
    // - FirstSuccessfulStrategy:第一个成功就停止
}

// 配置示例
@Bean  
public Authenticator authenticator() {
    ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
    
    // 设置认证策略
    authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
    
    // 设置多个Realm
    List<Realm> realms = Arrays.asList(
        new DatabaseRealm(),  // 数据库用户
        new LdapRealm(),     // LDAP用户  
        new ApiRealm()       // API用户
    );
    authenticator.setRealms(realms);
    
    return authenticator;
}

Authorizer(授权器)- “权限检查员”

简单理解: Authorizer负责检查用户是否有权限执行某个操作。

/**
 * Authorizer = 权限检查员  
 * 就像门卫,检查你是否有权限进入某个房间
 */
public interface Authorizer {
    boolean isPermitted(PrincipalCollection principals, String permission);
    boolean hasRole(PrincipalCollection principals, String roleIdentifier);
}

// 使用示例
public class UserController {
    
    @RequiresPermissions("user:create")  // 需要创建用户权限
    public String createUser() {
        return "创建用户成功";
    }
    
    @RequiresRoles("admin")  // 需要管理员角色
    public String adminPanel() {
        return "管理员面板"; 
    }
}

SessionManager(会话管理器)- “会话管家”

简单理解: SessionManager管理用户的会话信息,跟踪用户的登录状态。

/**
 * SessionManager = 会话管家
 * 就像酒店前台,管理客人的入住信息和房间状态
 */
public interface SessionManager {
    Session start(SessionContext context);
    Session getSession(SessionKey key);
    void touch(SessionKey key);
    void stop(SessionKey key);
}

// Web环境配置
@Bean
public SessionManager sessionManager() {
    DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
    sessionManager.setSessionTimeout(30 * 60 * 1000); // 30分钟超时
    sessionManager.setSessionIdCookieEnabled(true);
    sessionManager.setSessionIdUrlRewritingEnabled(false);
    return sessionManager;
}

CacheManager(缓存管理器)- “记忆助手”

简单理解: CacheManager缓存用户的认证和授权信息,提高系统性能。

/**
 * CacheManager = 记忆助手
 * 就像大脑的短期记忆,记住最近用过的信息
 */
public interface CacheManager {
    <K, V> Cache<K, V> getCache(String name);
}

// Redis缓存配置
@Bean
public CacheManager cacheManager() {
    RedisCacheManager cacheManager = new RedisCacheManager();
    cacheManager.setRedisManager(redisManager());
    cacheManager.setKeyPrefix("shiro:cache:");
    cacheManager.setExpire(1800); // 30分钟过期
    return cacheManager;
}

3. 认证和授权流程

认证流程(Authentication)- “你是谁?”

授权流程(Authorization)- “你能做什么?”

4. 实际应用示例

完整配置示例

@Configuration
public class ShiroConfig {
    
    // 1. 配置Realm(数据源)
    @Bean
    public MyRealm myRealm() {
        MyRealm realm = new MyRealm();
        realm.setCredentialsMatcher(hashedCredentialsMatcher()); // 密码匹配器
        realm.setCachingEnabled(true); // 启用缓存
        return realm;
    }
    
    // 2. 配置SecurityManager(总管)
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm());
        securityManager.setSessionManager(sessionManager());
        securityManager.setCacheManager(cacheManager());
        return securityManager;
    }
    
    // 3. 配置过滤器链
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        
        // 配置URL权限
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/login", "anon");      // 匿名访问
        filterChainDefinitionMap.put("/logout", "logout");   // 登出
        filterChainDefinitionMap.put("/admin/**", "roles[admin]"); // 需要admin角色
        filterChainDefinitionMap.put("/**", "authc");        // 需要认证
        
        shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilter;
    }
}

业务代码使用

@RestController
public class UserController {
    
    // 登录接口
    @PostMapping("/login")
    public Result login(@RequestBody LoginRequest request) {
        Subject subject = SecurityUtils.getSubject();
        
        try {
            UsernamePasswordToken token = new UsernamePasswordToken(
                request.getUsername(), 
                request.getPassword()
            );
            subject.login(token);
            return Result.success("登录成功");
        } catch (AuthenticationException e) {
            return Result.error("登录失败:" + e.getMessage());
        }
    }
    
    // 需要权限的接口
    @RequiresPermissions("user:view")
    @GetMapping("/users")
    public List<User> getUsers() {
        return userService.findAll();
    }
    
    // 需要角色的接口
    @RequiresRoles("admin")
    @DeleteMapping("/users/{id}")
    public Result deleteUser(@PathVariable Long id) {
        userService.delete(id);
        return Result.success("删除成功");
    }
    
    // 手动检查权限
    @GetMapping("/profile")
    public Result getProfile() {
        Subject subject = SecurityUtils.getSubject();
        
        if (subject.isPermitted("profile:view")) {
            String username = (String) subject.getPrincipal();
            User user = userService.findByUsername(username);
            return Result.success(user);
        } else {
            return Result.error("无权限访问");
        }
    }
}

5. 核心概念总结

概念作用比喻
Subject当前用户的代理银行柜台员工
SecurityManager安全总协调公司CEO
Realm数据源适配器翻译官
Authenticator身份验证机场安检
Authorizer权限检查门卫保安
SessionManager会话管理酒店前台
CacheManager性能优化大脑记忆

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇