Spring Boot(六):集成Shiro实现权限控制

Shiro是Apache旗下的一款产品,是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。Shiro在日常工作开发中并不少见,因为相较于Spring Security成熟但是复杂的开发体系而言,Shiro的上手只需要几天,而且在授权和验证的配置上比较简单。

  • Shiro整体架构

Shiro的整体架构如下图:

Subject:即“当前操作用户”。泛指当前操作的事务,不仅仅局限于“人”这一概念,可以使后台进程,账户等类似的,不过管理系统中,由于Shiro主要是做用户的授权和验证,所以可以粗略的人为Subjec为当前用户
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。

Shiro主要功能:

  • Authentication(认证):用户身份识别,通常被称为用户“登录”

  • Authorization(授权):访问控制。比如某个用户是否具有某个操作的使用权限。

  • Session Management(会话管理):特定于用户的会话管理,甚至在非web 或 EJB 应用程序。

  • Cryptography(加密):在对数据源使用加密算法加密的同时,保证易于使用。

介绍到此,开始进行项目实践

  • 引入依赖

<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
  • 表结构设计

总共五张表:用户、角色、权限表以及用户角色关联表,角色权限关联表,如下图:

  • shiro配置

继承AuthorizingRealm这个类后,会要求重写两个方法,一个是授权,一个是验证。

@Configuration
public class MyRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;

    /**
     * 授权
     *
     * @param principalCollection
     * @return authorizationInfo
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User user = (User) principalCollection.getPrimaryPrincipal();
        for (Role role : user.getRoleList()) {
            authorizationInfo.addRole(role.getRoleName());
            for (Permission permission : role.getPermissionList()) {
                authorizationInfo.addStringPermission(permission.getPermission());
            }
        }
        return authorizationInfo;
    }

    /**
     * 验证
     *
     * @param authenticationToken
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String username = (String) authenticationToken.getPrincipal();
        //Shiro有时间间隔机制,2分钟内不会重复执行该方法
        User user = userService.getUserByUserName(username);
        if (user != null) {
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUserName(), user.getUserPasswrod(), getName());
            return authenticationInfo;
        }
        return null;
    }
}

然后是Shiro的配置 ,注入完realm和securityManager后,编写过滤器栈。

@Configuration
public class ShiroConfig {
    @Bean
    public MyRealm myRealm() {
        MyRealm myRealm = new MyRealm();
        //如果有加密类操作,在这里执行
        return myRealm;
    }

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager(myRealm());
        return manager;
    }

    /**
     * 配置过滤器栈
     */
    @Bean
    public ShiroFilterFactoryBean filterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        //使用LinkHashMap保证有序执行
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //anon:可匿名访问
        //authc:需要认证
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setSuccessUrl("/index");
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 开启权限注解支持
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean(name = "simpleMappingExceptionResolver")
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
        Properties mapping = new Properties();
        mapping.setProperty("DatabaseExpection", "databaseError");
        mapping.setProperty("UnauthorizedException", "403");
        simpleMappingExceptionResolver.setExceptionMappings(mapping);
        simpleMappingExceptionResolver.setDefaultErrorView("error");
        simpleMappingExceptionResolver.setExceptionAttribute("ex");
        return simpleMappingExceptionResolver;
    }

}
  • controller层及测试

@Controller
public class LoginController {

    @RequestMapping({"/", "/index"})
    public String index() {
        return "/index";
    }

    @RequestMapping("/login")
    public String login(HttpServletRequest request, Map<String, Object> map) {
        String exception = (String) request.getAttribute("shiroLoginFailure");
        String msg = "";
        if (exception != null) {
            if (UnknownAccountException.class.getName().equals(exception)) {
                msg = "账号不存在";
            } else if (IncorrectCredentialsException.class.getName().equals(exception)) {
                msg = "密码错误";
            } else {
                msg = "其他错误" + exception;
            }
        }
        map.put("msg", msg);
        return "/login";
    }

    @RequestMapping("/403")
    public String unAuthorizedRole() {
        return "403";
    }

}
@Controller
@RequestMapping("user")
public class UserController {
    /**
     * 用户查询
     */
    @RequestMapping("/userList")
    @RequiresPermissions("user:view")
    public String userInfo() {
        return "userInfo";
    }

    /**
     * 用户添加;
     */
    @RequestMapping("/userAdd")
    @RequiresPermissions("user:add")
    public String userAdd() {
        return "userAdd";
    }

    /**
     * 用户删除;
     */
    @RequestMapping("/userDel")
    @RequiresPermissions("user:del")
    public String userDel() {
        return "userDel";
    }
}

访问:http://localhost:8080/login 显示登录界面

进去后根据不同的路径返回不同的结果

本文demo地址:https://github.com/hong52ni/SpringBoot-Demo-Aggregate

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

方木丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值