SpringBoot进阶(十)整合Shiro下篇

1,088 阅读3分钟

GitHub:github.com/baiyuliang/…

上篇完成了登录验证及授权,那么对于授权的作用还没有体现出来,这篇就结合shiro权限标签来说说授权后有哪些用途?! 接上篇,登录成功后:

在这里插入图片描述

我们可以试着点击一下下面的几个模块,可能会出现4xx的错误,这是因为我们还没有添加路径映射:

@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //浏览器请求映射到对应页面(ViewName代表对应的html)
        registry.addViewController("/").setViewName("login");
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/index").setViewName("index");
        registry.addViewController("/reg").setViewName("reg");
        registry.addViewController("user/userlist").setViewName("user/userlist");
        registry.addViewController("user/add").setViewName("user/add");
        registry.addViewController("user/edit").setViewName("user/edit");
        registry.addViewController("/level1").setViewName("level1/index");
        registry.addViewController("/level2").setViewName("level2/index");
        registry.addViewController("/level3").setViewName("level3/index");
    }

}

关于为什么都要添加映射,这里有个小坑...,就是在html页面使用shiro标签时,只有添加了映射的html页面才会有效(从shiro标签属性中获取用户信息)!另外,注意映射名不能与Controller中自己写的mappingurl冲突,比如我们之前可能在UserController中定了方法:

@RequestMapping("/user")
public class UserController {

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Integer id) {
        return userService.getUserById(id);
    }
}

那么这个方法就会跟:

registry.addViewController("user/userlist").setViewName("user/userlist");

冲突!因为他们用了同样的路由“user”,系统无法识别你在调用时到底用的是哪个,就会报错!(系统默认先从UserController访问,比如你输入http://xxx/user/userlist 时会提示你数据类型不对,不能传入字符串类型)

现在,如果我们使用admin登录的(user,role,permission三表大家要配置好,能提现不同角色差异即可),此时我们打开权限测试1、2、3模块都能正常打开,因为我们在ShiroConfig已经为相应角色分配了页面访问权限:

     map.put("/level1/**", "anyRoleFilter[user,admin,superadmin]");
     map.put("/level2/**", "anyRoleFilter[admin,superadmin]");
     map.put("/level3/**", "anyRoleFilter[superadmin]");

level1下的资源,user,admin,superadmin角色都可以访问; level2下的资源,只有admin,superadmin角色可以访问; level3下的资源,只有superadmin角色可以访问;

目前,我数据库中的user表数据:

在这里插入图片描述

角色id分别为1(superadmin),2(admin),3(user)。

使用admin账号登录,那么打开的效果如图:

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

换账号baiyuliang,其角色为admin,权限测试1,2都没问题,但是打开3:

在这里插入图片描述

403,拒绝访问,好,我们再用一个只有user权限的用户test登录:

在这里插入图片描述 在这里插入图片描述

这说明我们配置的角色访问资源限制已经生效!现在打开用户管理模块:

在这里插入图片描述

如果出现错误,那可能是你没有写获取用户列表的接口:

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

    User findByUsername(String username);

    Page<User> findAll(Specification<User> spec, Pageable pageable);

}
public interface UserService extends BaseService {

    User getUserByName(String username);

    ResponseData getUserList(Integer page,Integer limit);

    ResponseData logout();
}
    @Override
    public ResponseData getUserList(Integer page, Integer limit) {
        ResponseData responseData = new ResponseData();
        Specification<User> specification = (Specification<User>) (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        Pageable pageable = PageRequest.of(page - 1, limit);
        Page<User> userPage = userRepository.findAll(specification, pageable);
        responseData.setCode(1);
        responseData.setMsg("获取用户列表成功");
        responseData.setData(toList((int) userPage.getTotalElements(), userPage.getContent()));
        return responseData;
    }


    @Override
    public ResponseData logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return new ResponseData(1, "退出成功");
    }

    public Map<String, Object> toList(int total, List list) {
        Map<String, Object> map = new HashMap<>();
        map.put("list", list);
        map.put("total", total);
        return map;
    }

注意getUserList方法是做了分页的,具体可以下载项目参考,不是本篇文章重点,所以不做过多说明!

继续查看上图,我们可以看到admin是有添加、编辑和删除操作权限的,我们可以继续切换baiyuliang和test账号测试:

在这里插入图片描述 在这里插入图片描述

看出差别了吗?superadmin角色可以添加、编辑和删除,admin角色可以添加、编辑而不能删除,user角色就只有查看权限了!

这个判断的具体流程是什么呢?

1.我们在Shiro授权方法中:

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        Role role = roleService.getRoleById(user.getRoleId());
        simpleAuthorizationInfo.addRole(role.getName());//角色:superadmin,admin,user
        Permission permission = permissionService.getPermissionByRoleId(role.getId());;
        simpleAuthorizationInfo.addStringPermission(permission.getName());//添加权限
        return simpleAuthorizationInfo;
    }

根据登录用户,给其添加了角色和对应权限!

2.在html页面中,引入shiro标签:

<html xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

3.在需要判断不同角色显示不同模块时,添加shiro标签如: shiro:hasAnyRoles="superadmin,admin":

 <script type="text/html" id="toolbar">
     <div class="layui-btn-container" shiro:hasAnyRoles="superadmin,admin">
         <button class="layui-btn layui-btn-normal layui-btn-sm data-add-btn" lay-event="add">添加</button>
         <button class="layui-btn layui-btn-sm layui-btn-danger data-delete-btn" lay-event="delete" shiro:hasRole="superadmin">删除
         </button>
     </div>
 </script>

或shiro:hasRole="superadmin":

 <a class="layui-btn layui-btn-xs layui-btn-danger data-count-delete" lay-event="delete" shiro:hasRole="superadmin">删除</a>

其实这里我只用了角色判断,关于shiro更多属性,可以看提示:

在这里插入图片描述

很容易理解吧,大家需要用到什么属性,就可以直接使用了!

<shiro:principal property="username"/>

principal就是显示登录用户信息的,里面的内容就是你在做Shiro验证时,所保存的信息:

在这里插入图片描述

我们保存的是user对象,那么取值的时候property对应user的属性即可!关于更多Shiro的使用及配置,以及shiro标签的使用,大家可以多参考文档了!