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页面。

猜你喜欢

转载自www.cnblogs.com/yanmingyuan/p/10585017.html
今日推荐