频道栏目
首页 > 资讯 > 其他 > 正文

shiro权限框架详解 shiro与web项目整合(上)

17-02-10        来源:[db:作者]  
收藏   我要投稿

shiro权限框架详解 shiro与web项目整合(上):shiro和web项目整合,实现类似真实项目的应用,本文中使用的项目架构是springMVC+mybatis,所以我们是基于搭建好的项目进行改造的。

将shiro整合到web应用中 登录 退出 认证信息在页面展现,也就是显示菜单 shiro的过滤器

将shiro整合到web应用中

数据库脚步

sql脚步放到项目中,项目上传到共享的资源中,文章最后给出共享url。

去除项目中不使用shiro实现认证的拦截器

    
    
    
    
    
    

添加shiro的jar包

除了前面文章提到的shiro-core相关的jar包,还需要如下:

与web整合的 shiro-web-1.2.3.jar 与spring整合的 shiro-spring-1.2.3.jar 与ehcache整合的 shiro-ehcache-1.2.3.jar

在web.xml中配置shiro的filter

在web系统中,shiro 也是通过filter进行拦截的。filter拦截后将操作交给filterChain(过滤器炼)。shiro中提供了多个filter,在栏目 shiro的过滤器 会全部介绍
在web中配置filter,如下:

    
    
    
        shiroFilter
        org.springframework.web.filter.DelegatingFilterProxy
        
        
            targetFilterLifecycle
            true
        
        
        
            targetBeanName
            shiroFilter
        
    
    
        shiroFilter
        /*
    

新建applicationContext-shiro.xml文件

内容下图:

    
    
    
        
        
        
        
        
        
        
        
        
            
                
                /images/** = anon
                /js/** = anon
                /styles/** = anon
                
                /validatecode.jsp = anon
                
                /** = anon
            
        
    

    
    
        
    

    
    

上面配置的CustomRealm 的内容和文章shiro权限框架详解05-shiro授权的CustomRealm一样。

测试是否整合成功

在界面输入CustomRealm 代码中的账号为 zhangsan 密码为 123 可以进入欢迎页面。

但是并没有菜单和相关用户信息

登录功能

原理

由于登录使用的是 org.apache.shiro.web.filter.authc.FormAuthenticationFilter filter实现的,具体流程如下:
如果用户没有认证时,请求上面配置的loginUrl进行认证,用户的身份信息和密码提交到loginUrl,FormAuthenticationFilter拦截取出request中的username和password(参数的key是可以进行配置的,下一篇blog介绍)参数值。FormAuthenticationFilter调用realm传入一个token(包含username和password),realm根据username查询用户信息,如果查询不到,返回null,FormAuthenticationFilter向request域中填充一个参数,key为shiroLoginFailure 记录异常信息。如果不为空的话,返回AuthenticationInfo 类。

修改登录页面

由于FormAuthenticationFilter的身份信息和密码的请求参数的key默认是(username和password),修改login.jsp页面的账号和密码输入框name属性值,并注释掉验证码的代码。

修改controller类

修改LoginController 的 login 方法如下:

    @RequestMapping("/login")
    public String login(HttpServletRequest request)throws Exception{

        //如果登录失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名
        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 {
                throw new Exception();//最终在异常处理器生成未知错误
            }
        }
        //此方法不处理登录成功(认证成功),shiro认证成功会自动跳转到上一个请求路径。
        //登录失败还到login页面
        return "login";
    }

这个方法只有校验不通过的时候才会执行。真正的校验方法是在自定义的realm中,校验身份是否正确。

修改认证拦截器

将所有请求都改为需要认证才能访问的。


        
        
        
        
        
        
        
        
        
                
            
        

        
        
            
                
                /images/** = anon
                /js/** = anon
                /styles/** = anon
                /validatecode.jsp = anon

                
                /** = authc
            
        
    

验证登录功能

在登录界面输入账号为 zhangsan 密码为 123 验证是否登录成功,然后输入错误的账号,控制台出现下面的异常信息:
账号不存在异常
如果输入密码错误:
密码错误提示信息
异常信息和前面Java项目演示的一样。

退出

退出不需要我们自己实现,只要去访问一个退出的url(该url是可以不存在的)即可,由LogoutFilter filter处理,清除session。在applicationContext.xml配置logoutFilter

    
    
    
        
        
        
        
        
        
        
        
        
                
            
        

        
        
            
                
                /images/** = anon
                /js/** = anon
                /styles/** = anon
                /validatecode.jsp = anon
                
                /logout.action = logout
                
                /** = authc
            
        
    

删除原来的退出方法。

菜单显示

修改realm从数据库查询用户信息及用户拥有的菜单设置在AuthenticatorInfo中。具体代码如下:

    /**
     * 用于认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 
            throws AuthenticationException {
        //第一步:通过token获取身份信息
        String userCode = (String) token.getPrincipal();

        //从数据库中查询账号信息是否存在
        SysUser sysUser = null; 
        try {
            sysUser = sysService.findSysUserByUserCode(userCode);
        } catch (Exception e1) {
            e1.printStackTrace();
        }


        if(sysUser==null){
            return null;
        }

        //第二步:通过获取的身份信息进行数据库查询
        //模拟查询到的密码
        String password = sysUser.getPassword();

        //如果查询不到返回null


        //模拟数据activeUser就是用户身份信息
        ActiveUser activeUser = new ActiveUser();
        activeUser.setUserid("zhangsan");
        activeUser.setUsercode("zhangsan");
        activeUser.setUsername("张三");

        //查询菜单信息
        List menus = null;
        try {
            menus = sysService.findMenuListByUserId(sysUser.getUsercode());
        } catch (Exception e) {
            e.printStackTrace();
        }
        activeUser.setMenus(menus);

        //得到盐
        String salt = sysUser.getSalt();

        //如果查询到结果返回AuthenticationInfo
        AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(activeUser, password,ByteSource.Util.bytes(salt), "");

        return authenticationInfo;
    }

在自定义的realm中用到了前面章节中使用的散列算法和盐。

修改FirstAction中的first方法

修改代码将获取身份信息,并放入request域中用于页面显示。

    //系统首页
    @RequestMapping("/first")
    public String first(Model model)throws Exception{

        Subject subject =SecurityUtils.getSubject();
        ActiveUser activeUser =  (ActiveUser)subject.getPrincipal();
        model.addAttribute("activeUser", activeUser);
        return "/first";
    }

测试

这次是需要借助数据库才能登陆。你可以自己创建密码通过SELECT MD5('密码'+'盐') 获得加密后的密码。修改表 sys_user
如果成功的话,将会看到如下页面。
显示菜单的截图

shiro过滤器总结

过滤器简称 对应的Java类
anon org.apache.shiro.web.filter.authc.AnonymousFilter
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port org.apache.shiro.web.filter.authz.PortFilter
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl org.apache.shiro.web.filter.authz.SslFilter
user org.apache.shiro.web.filter.authc.UserFilter
logout org.apache.shiro.web.filter.authc.LogoutFilter

各个过滤器的介绍和作用:


anon:例子/admins/**=anon 没有参数,表示可以匿名使用。


authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,FormAuthenticationFilter是表单认证,没有参数 。


roles:例子 /admins/user/** =roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/** =roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。


perms:例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。


rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method],其中method为post,get,delete等。


port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString
是你访问的url里的?后面的参数。


authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证

相关TAG标签
上一篇:Java设计模式之行为型模式(状态模式)
下一篇:eclipse创建元模型
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站