zoukankan      html  css  js  c++  java
  • shiro入门(快速搭建、整合Springboot、登录拦截、用户认证、整合mybatis、用户授权、整合thymeleaf)

    查看官方文档shiro的10分钟快速搭建

    http://shiro.apache.org/10-minute-tutorial.html

    github查看shiro源码

    https://github.com/apache/shiro.git

    导入依赖、新建shiro.ini和log4j.properties配置文件,log4j非必须,最后编写启动类

    查看启动类QuickStart的源码,对比Security

    shiro三大核心对象

     

    Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。

    Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。

    SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。

    Realm:Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。

    从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。

    Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

    整合SpringBoot

    编写Shiro配置类和Realm配置类

    @Configuration
    public class ShiroConfig {
        //第三步 ShiroFilterFactoryBean
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultsecurityManager) {
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultsecurityManager);
            return bean;
        }
        //第二步 DefaultWebSecurityManager
        @Bean(name="securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //关联UserRealm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
        //第一步 创建Realm对象 ,需要自定义类
        @Bean
        public UserRealm userRealm(){
            return new UserRealm();
        }
    }
    public class UserRealm extends AuthorizingRealm {
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal){
            return null;
        }
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){
            return null;
        }
    }

    登录拦截(授权实现)

    编写登录页及controller

    <h1>登录</h1>
    <form th:action="@{/authentication}">
    用户名:<input type="password" name="username">
    密码:<input type="password" name="password">
    <p><input type="submit"></p>
    </form>
    <p th:text="${msg}" style="color:red"></p>
        @RequestMapping("/user/login")
        public String update(){
            return "user/login";
        }

    shiro配置类中加入登录拦截器,没有权限则跳转到登录页

        //第三步 ShiroFilterFactoryBean
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultsecurityManager) {
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultsecurityManager);
    
            //添加Shiro的内置过滤器
            /*
                anon:无需认证即可访问
                authc:认证访问
                user:使用remember me功能才能访问
                perms:拥有对某个资源的权限才能访问
                role:拥有某个角色权限才能访问
             */
    
            Map<String,String> filterMap = new LinkedHashMap<>();
    
            //设置权限
            filterMap.put("/user/add","authc");
            filterMap.put("/user/update","authc");
    
            bean.setFilterChainDefinitionMap(filterMap);
    
            //设置登录请求
            bean.setLoginUrl("/user/login");
    
    
            return bean;
        }

    测试效果,点击主页的add或update会跳转至登录页

     

     用户认证

     配置登录提交用户名密码的认证,先配置controller,再配置Realm认证类

        @RequestMapping("/authentication")
        public String authentication(String username,String password,Model model){
            //获取当前的用户
            Subject subject = SecurityUtils.getSubject();
    
            //封装用户的登录数据
            UsernamePasswordToken token = new UsernamePasswordToken(username,password);
    
            //执行登录方法,捕获异常
            try {
                subject.login(token);
                return "index";
            } catch (UnknownAccountException e) {
                model.addAttribute("msg","用户名错误");
                //用户名不存在
                e.printStackTrace();
                return "/user/login";
            }catch (IncorrectCredentialsException e) {
                model.addAttribute("msg","密码错误");
                //密码不存在
                e.printStackTrace();
                return "/user/login";
            }
    
        }
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){
            System.out.println("====执行了认证方法doGetAuthenticationInfo====");
    
            //用户名密码
            String username = "root";
            String password = "123";
    
            //此处AuthenticationToken为全局对象 subject.login()时传入
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
    
            if(!userToken.getUsername().equals(username)){
                return null;//抛出异常 UnknownAccountException
            }
    
            return new SimpleAuthenticationInfo("",password,"");
        }

    整合Mybatis

    mybatis与springboot整合见:SpringBoot中的数据访问(JDBC、Druid、Mybatis整合)

    整合后shiro从DB获取用户的数据,修改对应的认证过程

        
      //注入UserDao
    @Autowired
      private UserDao userDao;

    //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){ System.out.println("====执行了认证方法doGetAuthenticationInfo===="); //此处AuthenticationToken为全局对象 subject.login()时传入 UsernamePasswordToken userToken = (UsernamePasswordToken) token; List<User> userList = userDao.selectUser(); for (User user:userList) { if(!userToken.getUsername().equals(user.getName())){ continue; }else{ return new SimpleAuthenticationInfo("",user.getPwd(),""); } } return null;//抛出异常 UnknownAccountException }

     用户授权

    User类新增perm字段,增加相应的测试数据

    重新设置权限,同时设置未经授权的处理

    //设置权限
    filterMap.put("/user/add","perms[user:add]");
    filterMap.put("/user/update","perms[user:update]");
    //设置未经授权请求
    bean.setUnauthorizedUrl("/noauth");

    controller编写未经授权提示

        @ResponseBody
        @RequestMapping("/noauth")
        public String unauthorized(){
            return "未经授权";
        }

    在认证信息类返回对象中加入参数user,使授权类通过Subject获取user对象中的perm属性,使用perm属性进行用户权限设置

        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal){
    
            System.out.println("====执行了授权方法doGetAuthorizationInfo====");
    
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
            //拿到当前登录的对象
            Subject subject = SecurityUtils.getSubject();
            User user = (User)subject.getPrincipal();
    
            //设置当前用户权限
            info.addStringPermission(user.getPerm());
            return info;
        }
    
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){
            System.out.println("====执行了认证方法doGetAuthenticationInfo====");
    
            //此处AuthenticationToken为全局对象 subject.login()时传入
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
    
            List<User> userList = userDao.selectUser();
    
            for (User user:userList) {
    
                if(!userToken.getUsername().equals(user.getName())){
                    continue;
                }else{
                    return new SimpleAuthenticationInfo(user,user.getPwd(),"");
                }
    
            }
    
            return null;//抛出异常 UnknownAccountException
        }

    整合thymeleaf

    加入依赖

            <dependency>
                <groupId>com.github.theborakompanioni</groupId>
                <artifactId>thymeleaf-extras-shiro</artifactId>
                <version>2.0.0</version>
            </dependency>

    shiro配置类中加入整合方法

        //整合thymeleaf
        @Bean
        public ShiroDialect getShiroDialect(){
            return new ShiroDialect();
        }

    认证通过后向shiro的session中加入属性,提供给前端显示按钮时做判断

        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){
            System.out.println("====执行了认证方法doGetAuthenticationInfo====");
    
            //此处AuthenticationToken为全局对象 subject.login()时传入
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
    
            List<User> userList = userDao.selectUser();
    
            for (User user:userList) {
    
                if(!userToken.getUsername().equals(user.getName())){
                    continue;
                }else{
                    //认证通过后向shiro的session中加入属性,提供给前端显示按钮时做判断
                    Subject currentsub = SecurityUtils.getSubject();
                    Session session = currentsub.getSession();
                    session.setAttribute("loginUser",user);
    
                    return new SimpleAuthenticationInfo(user,user.getPwd(),"");
                }
    
            }
    
            return null;//抛出异常 UnknownAccountException
        }

    页面加入shiro申明,使用shiro标签控制显示

  • 相关阅读:
    while for循环
    Python模块
    python内置函数
    【简介】《GM/T 0034-2014 基于SM2密码算法的证书认证系统密码及其相关安全技术规范》
    Markdown的Diagrams
    密码设备管理-对称密钥管理
    TortoiseSVN的简单使用
    Android Studio安装后的设置
    Android Studio升级后,新建Activity后setContentView(R.layout.activity_layout_main);中R变红
    简介Floyd算法
  • 原文地址:https://www.cnblogs.com/alanchenjh/p/12341352.html
Copyright © 2011-2022 走看看