zoukankan      html  css  js  c++  java
  • Shiro入门之一 -------- Shiro权限认证与授权

    一  将Shirojar包导入web项目

    二 在web.xml中配置shiro代理过滤器

    注意: 该过滤器需要配置在struts2过滤器之前

      <!-- 配置Shiro的代理过滤器 -->
      <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>

    三 在spring的配置文件applicationContext.xml中配置Shiro的过滤器

    注意:过滤器ShiroFilterFactoryBean的id必须与web.xm中的过滤器name属性值一致

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
           <!-- 注入shiro的安全管理员 -->
           <property name="securityManager" ref="securityManager"></property>
           <!--

        注入登录路径

        loginUrl :没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,

        不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。

       -->
           <property name="loginUrl" value="/login.jsp"></property>
           <!--

        注入登录成功的路径

        successUrl :登录成功默认跳转页面,不配置则跳转至”/”。如果登陆前点击的一个需要登录的页面,

        则在登录自动跳转到那个需要登录的页面。不跳转到此。

       -->
           <property name="successUrl" value="/index.jsp"></property>
           <!--

        注入权限不足的路径

        unauthorizedUrl :没有权限默认跳转的页面。

       -->
           <property name="unauthorizedUrl" value="/unauthorizedUrl.jsp"></property>
           <!-- url权限级别的控制 -->
           <property name="FilterChainDefinitions">
               <value>

            

        <!-- 对页面应用的css文件放行 anon表示不需要任何权限就能访问 -->
                   /css/** = anon

        <!-- 对页面应用的js文件放行 -->
                   /js/** = anon

        <!-- 对页面应用的图片images文件放行 -->
                   /images/** = anon

        <!-- 对页面应用的验证码jsp文件,jsp后面加*号是在验证码jsp后面跟参数也放行 -->
                   /validatecode.jsp* = anon

        <!-- 对页面应用的登录页面放行 -->
                   /login.jsp* = anon

        <!-- 对页面应用的登录提交的login.action类放行 -->
                   /user_login* = anon

        <!-- 对访问staff.action设置权限限制 -->
                   /page_base_staff.action = perms[staff]

        <!-- 对其他上面没有设置的路径设置权限设置 -->

        <!--  过滤器链的执行顺序是自上而下依次匹配, 如果能匹配上, 则不再往下匹配  -->
                   /** = authc
               </value>
           </property>
        </bean>

    四 在登录方法中,编写Shiro相关的代码

    //登录功能
        public String login () {
            HttpServletRequest request = ServletActionContext.getRequest();
            //1.验证码校验
            String validateCode = (String) request.getSession().getAttribute("key");
            if (StringUtils.containsWhitespace(checkcode) || !validateCode.equalsIgnoreCase(checkcode)) {
                //1.1如果校验不成功,跳转到登录页面,并提示"验证码不正确的信息"
                this.addActionError(this.getText("checkCodeError"));
                return "login";
            }
            //2.如果校验成功实现登录功能
            //创建subject权限对象

       //Subject 是与程序进行交互的对象,可以是人也可以是服务或者其他,通常就理解为用户。
       //所有Subject 实例都必须绑定到一个SecurityManager上。我们与一个 Subject 交互,

       //运行时shiro会自动转化为与 SecurityManager交互的特定 subject的交互。

            Subject subject = SecurityUtils.getSubject();
            //创建用户名和密码的令牌
            String username = model.getUsername();
            String password = model.getPassword();
            password = MD5Utils.md5(password);
            AuthenticationToken token = new UsernamePasswordToken(username, password);
            //调用安全管理器
            try {
                subject.login(token);
                //从subject中获取保存在安全管理员中的user对象
                User user = (User) subject.getPrincipal();

         //将用户保存在session中,因为自定义拦截器的原因(如果没有自定义拦截器, 将用户存放在session域中的这个步骤可以省略)
                request.getSession().setAttribute("loginUser", user);
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                this.addActionError(this.getText("usernameError"));
                return "login";
            } catch (AuthenticationException e) {
                e.printStackTrace();
                this.addActionError(this.getText("passwordError"));
                return "login";
            }
            return "home";
        }

     五 创建Realm安全数据桥, 通过继承AuthorizingRealm的方式实现

     public class BOSRealm extends AuthorizingRealm {
        @Resource
        private IUserDao userDao;

        //权限认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken paramAuthenticationToken)
                throws AuthenticationException {
            UsernamePasswordToken token = (UsernamePasswordToken) paramAuthenticationToken;
            String username = token.getUsername();

       //调用userdao根据用户名查询用户
            User user = userDao.findByUsername(username);
            if (user != null) {
                //如果查询的用户存在
                //TODO 与数据库中用户名和密码进行比对。比对成功则返回info,比对失败则抛出对应信息的异常AuthenticationException
                SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,
                        user.getPassword(), this.getClass().getName());
                return authenticationInfo;
            } else {

        //如果查询不到用户, 返回空, Shiro会抛出UnknownAccountException异常
                return null;
            }
        }
        
        //授予权限
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection paramPrincipalCollection) {
            // TODO Auto-generated method stub
            return null;
        }

    }

     六  在Spring配置文件applicationContext.xml中配置Shiro安全管理器

    <!-- 7配置Shiro的安全管理器 -->
        <bean name="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
           <!-- 注入realm数据桥 -->
           <property name="realm" ref="bosRealm"></property>
        </bean>

    <!--  配置Realm数据桥对象  -->
        <bean id="bosRealm" class="cn.rodge.bos.shiro.BOSRealm"></bean>

    七  在自定义Realm中, 为当前用户授权

    在Shiro权限认证之后, 认证过的用户对于特定权限的页面或者功能仍然不具备访问权限, 此时就需要针对不同的用户进行相应的授权操作. Shiro的授权操作是在权限认证的基础之上完成的. 需要修改BOSRealm类中的权限授予的方法.

    //授予权限
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection paramPrincipalCollection) {
            //创建授权信息对象
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            //根据当前用户查询数据库,获取其权限对象
            //获取当前用户,由于shiro的过滤器在struts的过滤器之前执行,因此此时的用户还没有被封装到session中,
            //故获取当前用户在session中娶不到
            /*Subject subject = SecurityUtils.getSubject();
            User loginUser = (User) subject.getPrincipal();*/
            User loginUser = (User) paramPrincipalCollection.getPrimaryPrincipal();
            if (loginUser != null) {
                List<Function> list = null;
                //表示用户存在,调用roledao根据用户查询所有权限
                if ("admin".equals(loginUser.getUsername())) {
                    //如果是超级管理员,赋予所有权限
                    list = functionDao.findAll();
                } else {
                    //根据用户id查询所有权限
                    list = functionDao.findFunctionByUserId(loginUser.getId());
                }
                if (list != null && list.size() > 0) {
                    for (Function function : list) {

           //为用户授权
                        simpleAuthorizationInfo.addStringPermission(function.getCode());
                    }
                }
                return simpleAuthorizationInfo;
            } else {
                return null;
            }
        }

    七  查询用户权限的dao层方法

      @SuppressWarnings("unchecked")
        @Override
        //根据用户id查询权限
        public List<Function> findFunctionByUserId(String id) {
            String hql = "from Function f left outer join fetch f.roles r "
                    + "left outer join fetch r.users u where u.id = ?";
            return this.getHibernateTemplate().find(hql, id);
        }

  • 相关阅读:
    基础练习 分解质因数
    基础练习 矩阵乘法
    基础练习 矩形面积交
    基础练习 完美的代价
    设计模式完结(7)--桥接模式----处理多维度变化
    设计模式完结(6)--适配器模式----不兼容结构的协调
    设计模式完结(5)-建造者模式
    设计模式完结(4)-原型模式
    设计模式完结(3)单例模式
    设计模式读完总结(2)工厂模式
  • 原文地址:https://www.cnblogs.com/rodge-run/p/6445963.html
Copyright © 2011-2022 走看看