SpringBoot(42) —— Shiro请求授权实现

    科技2022-07-16  122

    目录

    1.Shiro开启资源授权访问2.授予用户权限3.小结


    1.Shiro开启资源授权访问

    现在我们的两个连接add和update都只是要求用户认证,认证之后就可以正常访问了,但是在真实业务中资源除了和认证挂钩之外,还与授权有关,对于有些资源,只有你拥有对应的角色你才能去访问,否则你没有权限去访问在spring security中你只需要在自定义的config类中configure(HttpSecurity http)方法中调用 http.authorizeRequests()方法就可以实现对某一资源的授权访问在shiro中,对于资源的授权管理通过使用过滤器实现,授权需要使用过滤器perms /* * - anon:无需认证即可访问 * - authc:必须认证才能访问 * - user:必须有"记住我"功能才能访问【几乎不用】 * - perms:拥有对某个资源的访问权限才能访问【比如某系资源只有管理员可以访问】 * - role:拥有某个角色才能访问 * */ filterMap.put("/user/add","perms[user:add]"); //表示用户角色为user,并且拥有add权限的用户可以请求到"/user/add"对应的资源 上面的代码就相当于添加了权限控制,对于URL"/user/add"的请求配置了权限控制,没有对应的角色和权限不能对资源进行请求;我们成功登陆admin用户,对add和update资源进行请求 但是正常情况下即使是未授权也不是跳转上面那样的未授权页面,而是跳转我们自定义的页面提醒用户未授权创建未授权页面Unauthorized.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>未授权</title> </head> <body> <h1>对不起,您没有访问该资源的权限,如需访问该资源,请联系管理员</h1> </body> </html> controller编写跳转方法@RequestMapping("/Unauthorized") public String Unauthorized(){ //未授权页面跳转 return "Unauthorized"; } 设置shiro在未授权情况下跳转到我们指定的页面 ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //设置安全管理器 bean.setSecurityManager(securityManager); bean.setUnauthorizedUrl("/Unauthorized"); 测试 未授权页面设置成功,但是还需要注意一点,我们在进入这个需要授权才能访问的页面的时候,控制台输出了一行字符串 这一行字符串打印输出是写在realm的授权方法中 这表明在访问需要授权的资源的时候会自动调用realm中的授权方法

    2.授予用户权限

    我们现在是把授权功能开启了,但是我们并没有将add资源访问需要的权限授予用户,所以现在所有的用户等不能访问我们的add资源,所以我们现在需要对用户进行授权操作可以授权的地方就是realm中,这个类里面的方法doGetAuthorizationInfo()专门用于向用户授权//授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("执行了授权========>doGetAuthorizationInfo"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//用于向用户授权的类对象 info.addStringPermission("user:add");//通过字符串向用户授权,授予了用户user角色,并且有了add的权限 return info ; } 测试 但是现在的问题是:我不管登陆哪个用户,都可以访问add资源 这些显然不是我们想要的,原因就是我们在授权方法中进行了硬编码,就是我们将授权的代码直接固定的写在了代码中,这导致每次有用户进入要进行权限验证的时候,进入这个方法,都会被加上权限"user:add",这就是对应的访问add资源需要的权限,所以所有的用户都可以获取到这个权限,就都可以访问add资源,这就导致我们为add资源在config中设置的权限验证失效了正常的做法是,我们应该从数据库中查询当前请求add资源的用户的权限,如果它的权限包含了"user:add",那么就让他访问add资源,如果没有该权限就直接跳转未授权页面所以我们需要改造我们的user数据表,加上一个表示这个用户权限的字段perms 新增POJO的字段package com.thhh.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class User { private Integer id; private String name; private String pwd; private String perms; } 现在我们要做的就是在用户请求需要授权的资源的时候,我们需要在doGetAuthorizationInfo()中拿到当前请求该资源的用户的权限,并判断他是否有这个权限去请求该资源但是问题是我们的用户数据是在doGetAuthenticationInfo()方法中查询的,那么怎么将方法doGetAuthenticationInfo()中查询到的数据传到方法doGetAuthorizationInfo()呢? 这个时候就需要使用doGetAuthenticationInfo()最后返回值来实现了 return new SimpleAuthenticationInfo(user,user.getPwd(),""); 对于这个构造方法我们可以查看源码public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) { this.principals = new SimplePrincipalCollection(principal, realmName); this.credentials = credentials; } * @param principal 从数据库中查询出的用户对象,用于唯一表示用户 * @param credentials 用户的密码,用于和前端填写的密码进行对比 * @param realmName 当前realm的名称,不传就写"" * * 这个构造还有多个重载 这里注意第一个参数,我们可以将从数据库中查询到的user对象传递进去,然后再在doGetAuthorizationInfo()中获取//授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("执行了授权========>doGetAuthorizationInfo"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); Subject subject = SecurityUtils.getSubject(); //获取当前对象 User principal = (User) subject.getPrincipal(); //获取当前对象的唯一标识符,即我们传入的user对象,从SimpleAuthenticationInfo的构造中传入的 info.addStringPermission(principal.getPerms()); //获取user权限,并赋予给当前请求需要授权才能访问的资源的用户 return info; //将SimpleAuthorizationInfo,即对于用户的授权信息返回,如果我们在上面进行的授权操作授予的权限/用户本身具有的权限包括了请求当前资源的权限,那么资源请求成功,如果不包含就请求失败 }

    注意:刚刚为数据库中用户添加权限的时候为root用户添加了update资源的请求权限,所以我们要去config中加上对于资源update请求的授权验证filterMap.put("/user/add","perms[user:add]"); filterMap.put("/user/update","perms[user:update]"); 测试

    测试成功!


    3.小结

    shiro中我们需要使用过滤器开启资源访问的权限控制用户的授权实在用户访问需要权限才能访问的资源的时候授予当前用户的,即用户首先通过认证,认证之后如果要请求需要权限才能访问的资源的时候,就在realm中的doGetAuthorizationInfo()中将用户存在数据库中的权限查询出来授予他,如果他存于数据库中的权限包括了请求当前资源的权限,那么就将请求的资源传给用户,如果不包括,就将用户重定向到未授权页面
    Processed: 0.009, SQL: 8