Shiro用法详解

极客

Shiro用法详解:别怕,这篇带你从入门到装X(内附实战踩坑记录)

嘿,朋友们!今天咱们来聊聊Shiro这个“老古董”但依然坚挺的安全框架,说实话,我第一次接触Shiro的时候,那叫一个头大,什么Subject、SecurityManager、Realm,听着就像在念魔法咒语,但用久了你会发现,这家伙其实就是个“门卫大爷”,逻辑简单得很!来,我带你捋一捋,保证你读完会“啊哈,原来就这么回事!”

Shiro用法详解

Shiro是什么?我为什么要用它?

先别急着敲代码,咱得先搞清楚它解决啥问题,简单说,Shiro就是帮你管“登录验证”和“权限控制”的,你想想,要是每个项目都得自己写Session管理、密码加密、角色判断,那不得累死?而且写得还不一定安全,Shiro就像个贴心的管家,你告诉它“谁能进哪个房间,能碰哪些东西”,剩下的事它全包了。

它的核心三板斧:

  • Subject(当前用户):代表“正在操作的人”,管他是登录了还是游客。
  • SecurityManager(安全管家):核心大脑,负责协调所有模块。
  • Realm(数据源):相当于“户口本”,告诉Shiro用户信息去哪儿查(数据库、LDAP都行)。

是不是感觉有点像MVC?对味了,它就是这种分层思维。

快速上手:十分钟跑通认证功能

来来来,光说不练假把式,咱们用Spring Boot整合Shiro,三步走:

第一步:引入依赖(Maven坐标别搞错)

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-starter</artifactId>
    <version>1.9.1</version>
</dependency>

第二步:写个Realm(最关键的!) 这里我栽过跟头,大家注意:Realm里doGetAuthenticationInfo负责验证登录,doGetAuthorizationInfo负责授权,千万别把逻辑写反了,不然你会哭的。

public class MyRealm extends AuthorizingRealm {
    // 授权:查询当前用户的角色和权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRole("admin");  // 实际开发中,这里从数据库查
        info.addStringPermission("user:delete");
        return info;
    }
    // 认证:验证用户名密码
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        // 从数据库查用户,密码要加密存储!
        String passwordFromDB = getPasswordByUsername(username);
        if (passwordFromDB == null) {
            throw new UnknownAccountException("兄弟,你账号不存在啊!");
        }
        return new SimpleAuthenticationInfo(username, passwordFromDB, getName());
    }
}

第三步:配置SecurityManager + 过滤器链 这一步最容易被忽略,尤其是过滤器链顺序,真是一失足成千古恨,记住这句口诀:“匿名在前,认证在后,权限最后”。

@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
    ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
    bean.setSecurityManager(securityManager);
    // 拦截路径配置
    Map<String, String> filterChain = new LinkedHashMap<>();
    filterChain.put("/login", "anon");      // 登录页放行
    filterChain.put("/logout", "logout");    // 退出
    filterChain.put("/admin/**", "authc, roles[admin]"); // 需要登录且是管理员
    filterChain.put("/**", "authc");         // 其余都要登录
    bean.setFilterChainDefinitionMap(filterChain);
    bean.setLoginUrl("/login");  // 没登录就跳这儿
    bean.setUnauthorizedUrl("/403"); // 没权限跳这儿
    return bean;
}

你看,核心就这些,是不是没那么玄乎?

进阶玩法:注解权限(装X必备)

有时候你想在方法级别控制权限,只有VIP才能调用这个接口”,这时候就得上@RequiresPermissions注解了。

@RestController
public class UserController {
    @GetMapping("/deleteUser")
    @RequiresPermissions("user:delete")
    public String deleteUser() {
        return "删除成功!";
    }
}

但注意啦!如果你在Spring Boot里用注解,必须在配置类上加上@EnableShiroAnnotations,不然控制器方法上的注解就是空摆设,我当时没加这个注解,还纳闷为啥权限没生效,排查了半天,气死我了!

密码加密:别再用明文了,求你了!

很多新手直接存明文密码,看得我心惊肉跳,Shiro支持MD5加盐加密,咱们用HashedCredentialsMatcher配合Realm使用。

@Bean
public HashedCredentialsMatcher matcher() {
    HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
    matcher.setHashAlgorithmName("MD5");
    matcher.setHashIterations(1024); // 加密次数,越多越安全
    return matcher;
}

然后在Realm里设置:

setCredentialsMatcher(matcher); // 在构造器或setter里

存密码的时候记住:新密码 = MD5(原密码 + 用户名盐值),这样就算数据库泄露,黑客拿到也是密文,一辈子都解不开。

实战避坑指南(血泪经验)

  1. Session超时问题:Shiro默认把Session存在内存里,重启就丢,你要是做集群部署,得用Redis缓存Session,不然用户登录状态一会儿就没,体验极差!
  2. 过滤器顺序shiroFilter里的Map一定要用LinkedHashMap,别用HashMap,否则顺序乱了,拦截规则全乱套。
  3. 跨域问题:前后端分离时,Shiro的Session机制会拦着OPTIONS请求,你得在过滤器链里放行/api/**的OPTIONS请求,不然前端哭死。
  4. 记住我功能:如果你设置user过滤器,记得同时创建rememberMeManager,不然“记住我”功能就失效了,用户每次打开浏览器都得重新登录。

Shiro是淘汰了吗?

很多人说Spring Security更强大,但我个人觉得Shiro轻量、学习曲线平缓,对于中小型项目真的够用了,而且Shiro的社区资料多啊,出个Bug你随便一搜就有解决方案,不像新框架踩坑只能自己摸黑,如果你做的是大型金融项目,那还是老老实实上Spring Security吧。

说真的,写代码这事儿,没有绝对的好与坏,只有合不合适,Shiro就像一把瑞士军刀,小巧但够用,你把它玩明白了,面试的时候还能跟面试官聊聊权限设计的门道,岂不美哉?

好啦,今天的Shiro用法就唠到这儿,如果你在配置过程中遇到什么奇葩报错,评论区留言,咱们一起吐槽一起解决!下期见!

文章版权声明:除非注明,否则均为极客网安-咸鱼原创文章,转载或复制请以超链接形式并注明出处。

目录[+]