• shiro整合SpringMVC


    1.取消原springmvc认证和授权拦截器

    去掉springmvc.xml中配置的LoginInterceptor和PermissionInterceptor拦截器。

    2.web.xml添加shiro Filter

    <!-- shiro过虑器,DelegatingFilterProxy通过代理模式将spring容器中的bean和filter关联起来 -->
        <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <!-- 设置true由servlet容器控制filter的生命周期 -->
            <init-param>
                <param-name>targetFilterLifecycle</param-name>
                <param-value>true</param-value>
            </init-param>
            <!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean-->
            <init-param>
                <param-name>targetBeanName</param-name>
                <param-value>shiroFilter</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>shiroFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    View Code

    3.applicationContext-shiro.xml

    <!-- Shiro 的Web过滤器 -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />
            <!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->
            <property name="loginUrl" value="/login.action" />
            <property name="unauthorizedUrl" value="/refuse.jsp" />
            <!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
            <property name="filterChainDefinitions">
                <value>
                    <!-- 退出拦截,请求logout.action执行退出操作 -->
                    /logout.action = logout
                    <!-- 无权访问页面 -->
                    /refuse.jsp = anon
                    <!-- roles[XX]表示有XX角色才可访问 -->
                    /item/list.action = roles[item],authc
                    /js/** anon
                    /images/** anon
                    /styles/** anon
                    /validatecode.jsp anon
                    /item/* authc
                    <!-- user表示身份认证通过或通过记住我认证通过的可以访问 -->
                    /** = authc
                </value>
            </property>
        </bean>
    
        <!-- 安全管理器 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="userRealm" />
        </bean>
    
        <!-- 自定义 realm -->
        <bean id="userRealm" class="cn.itcast.ssm.realm.CustomRealm1">
        </bean>
    View Code

    securityManager:这个属性是必须的。

    loginUrl:没有登录认证的用户请求将跳转到此地址进行认证,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。

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

    4.自定义realm

    此realm先不从数据库查询权限数据,当前需要先将shiro整合完成,在上边章节定义的realm基础上修改。

    public class CustomRealm1 extends AuthorizingRealm {
    
        @Override
        public String getName() {
            return "customRealm";
        }
    
        // 支持什么类型的token
        @Override
        public boolean supports(AuthenticationToken token) {
            return token instanceof UsernamePasswordToken;
        }
    
        // 认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(
                AuthenticationToken token) throws AuthenticationException {
    
            // 从token中 获取用户身份信息
            String username = (String) token.getPrincipal();
            // 拿username从数据库中查询
            // ....
            // 如果查询不到则返回null
            if (!username.equals("zhang")) {// 这里模拟查询不到
                return null;
            }
    
            // 获取从数据库查询出来的用户密码
            String password = "123";// 这里使用静态数据模拟。。
            
            // 根据用户id从数据库取出菜单
            //...先用静态数据
            List<SysPermission> menus = new ArrayList<SysPermission>();;
            
            SysPermission sysPermission_1 = new SysPermission();
            sysPermission_1.setName("商品管理");
            sysPermission_1.setUrl("/item/queryItem.action");
            SysPermission sysPermission_2 = new SysPermission();
            sysPermission_2.setName("用户管理");
            sysPermission_2.setUrl("/user/query.action");
            
            menus.add(sysPermission_1);
            menus.add(sysPermission_2);
            
            // 构建用户身份信息
            ActiveUser activeUser = new ActiveUser();
            activeUser.setUserid(username);
            activeUser.setUsername(username);
            activeUser.setUsercode(username);
            activeUser.setMenus(menus);
    
            // 返回认证信息由父类AuthenticatingRealm进行认证
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                    activeUser, password, getName());
    
            return simpleAuthenticationInfo;
        }
    
        // 授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(
                PrincipalCollection principals) {
            // 获取身份信息
            ActiveUser activeUser = (ActiveUser) principals.getPrimaryPrincipal();
            //用户id
            String userid = activeUser.getUserid();
            // 根据用户id从数据库中查询权限数据
            // ....这里使用静态数据模拟
            List<String> permissions = new ArrayList<String>();
            permissions.add("item:query");
            permissions.add("item:update");
    
            // 将权限信息封闭为AuthorizationInfo
    
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            for (String permission : permissions) {
                simpleAuthorizationInfo.addStringPermission(permission);
            }
    
            return simpleAuthorizationInfo;
        }
    
    }
    View Code

    5.登录

    // 用户登陆提交
        @RequestMapping("/login")
        public String loginsubmit(Model model, HttpServletRequest request)
                throws Exception {
    
            // shiro在认证过程中出现错误后将异常类路径通过request返回
            String exceptionClassName = (String) request
                    .getAttribute("shiroLoginFailure");
            if(exceptionClassName!=null){
                if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
                    throw new CustomException("账号不存在");
                } else if (IncorrectCredentialsException.class.getName().equals(
                        exceptionClassName)) {
                    throw new CustomException("用户名/密码错误");
                } else if("randomCodeError".equals(exceptionClassName)){
                    throw new CustomException("验证码错误");
                } else{
                    throw new Exception();//最终在异常处理器生成未知错误
                }
            }
            return "login";
            
        }
    View Code

    6.首页

    由于session由shiro管理,需要修改首页的controller方法,将session中的数据通过model传到页面。

    //系统首页
        @RequestMapping("/first")
        public String first(Model model)throws Exception{
            
            //主体
            Subject subject = SecurityUtils.getSubject();
            //身份
            ActiveUser activeUser = (ActiveUser) subject.getPrincipal();
            model.addAttribute("activeUser", activeUser);
            return "/first";
        }
    View Code

    7.退出

    由于使用shiro的sessionManager,不用开发退出功能,使用shiro的logout拦截器即可。

    <!-- 退出拦截,请求logout.action执行退出操作 -->
    /logout.action = logout

    8.无权限refuse.jsp

    当用户无操作权限,shiro将跳转到refuse.jsp页面。

  • 相关阅读:
    null和undefined的区别
    减少页面加载时间的方法
    html5有哪些新特性、移除了那些元素?
    cookies,sessionStorage 和 localStorage 的区别
    小程序页面
    快速保存网页图片的工具
    Flex 布局教程
    第一阶段:Python开发基础 day08 Python基础语法入门--列表元组字典集合类型的内置方法
    第一阶段:Python开发基础 day08 数据类型的内置方法 课后作业
    python学习第一周知识内容回顾与小结
  • 原文地址:https://www.cnblogs.com/yanmingyuan/p/10585017.html
Copyright © 2020-2023  润新知