千家信息网

如何使用spring-shiro权限控制realm

发表于:2025-02-12 作者:千家信息网编辑
千家信息网最后更新 2025年02月12日,这篇文章主要介绍"如何使用spring-shiro权限控制realm",在日常操作中,相信很多人在如何使用spring-shiro权限控制realm问题上存在疑惑,小编查阅了各式资料,整理出简单好用的
千家信息网最后更新 2025年02月12日如何使用spring-shiro权限控制realm

这篇文章主要介绍"如何使用spring-shiro权限控制realm",在日常操作中,相信很多人在如何使用spring-shiro权限控制realm问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何使用spring-shiro权限控制realm"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

目录
  • spring-shiro权限控制realm

    • 用户与角色实体

    • Realm类

    • Shiro 配置类

    • 控制器

    • Service

  • shiro权限不生效原因分析

    • shiro遇到的坑

    • 问题原因:权限标签定义问题

spring-shiro权限控制realm

用户与角色实体

Role.java

@Data@Entitypublic class Role {    @Id    @GeneratedValue    private Integer id;    private Long userId;    private String role;}

User.java

@Data@Entitypublic class User {    @Id    @GeneratedValue    private Long id;    private String username;    private String password;}

Realm类

首先建立 Realm 类,继承自 AuthorizingRealm,自定义我们自己的授权和认证的方法。Realm 是可以访问特定于应用程序的安全性数据(如用户,角色和权限)的组件。

Realm.java

public class Realm extends AuthorizingRealm {    @Autowired    private UserService userService;    //授权    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {        //从凭证中获得用户名        String username = (String) SecurityUtils.getSubject().getPrincipal();        //根据用户名查询用户对象        User user = userService.getUserByUserName(username);        //查询用户拥有的角色        List list = roleService.findByUserId(user.getId());        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        for (Role role : list) {            //赋予用户角色            info.addStringPermission(role.getRole());        }        return info;    }    //认证    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        //获得当前用户的用户名        String username = (String) authenticationToken.getPrincipal();        //从数据库中根据用户名查找用户        User user = userService.getUserByUserName(username);        if (userService.getUserByUserName(username) == null) {            throw new UnknownAccountException(                    "没有在本系统中找到对应的用户信息。");        }        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),getName());        return info;    }}

Shiro 配置类

ShiroConfig.java

@Configurationpublic class ShiroConfig {    @Bean    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();        shiroFilterFactoryBean.setSecurityManager(securityManager);        Map filterChainDefinitionMap = new LinkedHashMap();        //以下是过滤链,按顺序过滤,所以/**需要放最后        //开放的静态资源        filterChainDefinitionMap.put("/favicon.ico", "anon");//网站图标        filterChainDefinitionMap.put("/**", "authc");        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);        return shiroFilterFactoryBean;    }    @Bean    public DefaultWebSecurityManager securityManager() {        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(myRealm());        return defaultWebSecurityManager;    }    @Bean    public MyRealm myRealm() {        MyRealm myRealm = new MyRealm();        return myRealm;    }}

控制器

UserController.java

@Controllerpublic class UserController {    @Autowired    private UserService userService;    @GetMapping("/")    public String index() {        return "index";    }    @GetMapping("/login")    public String toLogin() {        return "login";    }    @GetMapping("/admin")    public String admin() {        return "admin";    }    @PostMapping("/login")    public String doLogin(String username, String password) {        UsernamePasswordToken token = new UsernamePasswordToken(username, password);        Subject subject = SecurityUtils.getSubject();        try {            subject.login(token);        } catch (Exception e) {            e.printStackTrace();        }        return "redirect:admin";    }    @GetMapping("/home")    public String home() {        Subject subject = SecurityUtils.getSubject();        try {            subject.checkPermission("admin");        } catch (UnauthorizedException exception) {            System.out.println("没有足够的权限");        }        return "home";    }    @GetMapping("/logout")    public String logout() {        return "index";    }}

Service

UserService.java

@Servicepublic class UserService {    @Autowired    private UserDao userDao;    public User getUserByUserName(String username) {        return userDao.findByUsername(username);    }    @RequiresRoles("admin")    public void send() {        System.out.println("我现在拥有角色admin,可以执行本条语句");    }}

shiro权限不生效原因分析

shiro遇到的坑

-项目中使用shiro做登录校验和权限管理,在配置权限时遇到小坑,记录一下。

  • 环境:springboot+freemarker+shiro

  • 场景:后台管理,配置菜单以及按钮权限,分为三个层级,一二级暂时只考虑是否查看权限,第三层级为页面按钮权限,分增删改查。详情看图

  • 问题:一二层级正常,第三层级权限不起作用!

权限标签定义如下:

标签定义页面一页面二
第一层级one:viewtwo:view
第二层级one:page1:viewtwo:page2:view
第三层级one:page1:view:addtwo:page2:view:add

开始怀疑是数据库没有录入,查看后权限标签与角色已对应,排除。

后面怀疑是页面问题,后面把第三层级标签与第一二层级同一页面,依然不起作用,排除。

后面怀疑是权限标签定义问题,把第三层级标签改为one:page1:data:add,奇迹出现,权限生效。证实权限标签定义出了问题。

问题原因:权限标签定义问题

但是后来想想为什么会出现这种问题,每个标签都是独一无二的,对此我对shiro对于权限标签的校验产生了兴趣,查看源码,一路debug后最终在org.apache.shiro.authz.permission中看到了关键所在,核心代码如下

//当这个方法返回true时说明有此权限//这个p是代表当前循环匹配到的权限标签public boolean implies(Permission p) {// By default only supports comparisons with other WildcardPermissionsif (!(p instanceof WildcardPermission)) {return false;}    WildcardPermission wp = (WildcardPermission) p; //把当前标签转分割成一个set集合(如one:page1:view:add 会分割成[[one], [page1], [view], [add]])    List> otherParts = wp.getParts();    int i = 0; //循环匹配权限标签    for (Set otherPart : otherParts) {        // If this permission has less parts than the other permission, everything after the number of parts contained        // in this permission is automatically implied, so return true  //当全部循环匹配完没有返回false,则返回true,这个getparts()方法是获取当前角色当前循环的权限标签([[one], [page1], [view]])        if (getParts().size() - 1 < i) {            return true;        } else {            Set part = getParts().get(i);   /*如果包含有'*'而且不包含当前分割后的标签则返回false,    *当用户可以查看页面,也就是说当前角色拥有one:page1:view标签    *这里【!part.contains(WILDCARD_TOKEN)】返回true,第二个【part.containsAll(otherPart)】one会跟当前标签匹**配one,    *也就是说这里全部循环完返回的都是false,所以最后都没true,于是在上面返回了一个true。            if (!part.contains(WILDCARD_TOKEN) && !part.containsAll(otherPart)) {                return false;            }            i++;        }    }

小结一下:通过分析,我们看到了shiro在定义权限标签时,要主意匹配问题,不要存在包含问题,类似aaa 和aaab ,会导致后面标签失效。

到此,关于"如何使用spring-shiro权限控制realm"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0