zoukankan      html  css  js  c++  java
  • 构建 shiro struts2 spring3 mybatis 的maven项目

    书接上回 构建 struts2 spring3 mybatis 的maven项目 构建 pom.xml  

    继续在原有框架下 融合shiro ,具体shiro是啥 这里就不解释了,恩 反正功能挺强大的

    本着先会用再深入的原则,还是尝试着将shiro融入框架中

    0 首先上下这个项目的整体结构图

    1 在导入shiro的jar包  在pom.xml中添加shiro的配置

    ...
       <shiro.version>1.2.1</shiro.version>
    ...
      <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>${shiro.version}</version>
      </dependency>
      <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>${shiro.version}</version>
      </dependency>
      <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-ehcache</artifactId>
        <version>${shiro.version}</version>
      </dependency>
      <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>${shiro.version}</version>
      </dependency>
      </dependencies>

    2 在web.xml中导入 shiro的过滤器

    <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <init-param>
                <param-name>targetFilterLifecycle</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>shiroFilter</filter-name>
            <url-pattern>/*</url-pattern>
            <dispatcher>REQUEST</dispatcher>
            <dispatcher>FORWARD</dispatcher>
        </filter-mapping>

    这里要说明一下

    shiro的过滤器是前置过滤器,需要添加在struts2的前面,如果放在struts2之后会报错

    然后是在spring的过滤配置中添加spring-shiro的配置文件

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
             classpath:applicationContext-*.xml
        </param-value>
      </context-param>

    配置文件为applicationContext-shiro.xml, 因为这里用了通配符 所以不用修改

    3 然后 添加spring-shiro的配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans...>  
       
       <description>Shiro安全配置   来源于: http://shiro.apache.org/spring.html </description>
    
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="shiroDbRealm" />
        </bean>
        <bean id="shiroDbRealm" class="lqb.shiro.ShiroDbRealm" />
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />
            <property name="loginUrl" value="/login_loginPage.do" /> <!-- 没有权限或者失败后跳转的页面 -->
            <property name="successUrl" value="/login_home.do" />
            <property name="unauthorizedUrl" value="/other_error.do"/> 
            <property name="filterChainDefinitions">
                <value>
    
                /login_loginPage.do = anon
                
                /login_login.do = anon
                /login_home.do=authc
                /login_hello.do=authc
                
                /t1/**=roles[aa],perms[aaa]
                /t2/**=roles[bb],perms[baaa]
                /t3/**=roles[dd]
                
                </value>
            </property>
        </bean>
    
        <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
        
        
        <!-- AOP式方法级权限检查 -->
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
             <property name="proxyTargetClass" value="true" />   
        </bean>
        <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="securityManager" ref="securityManager"/>
        </bean>
        
        
    </beans>

     这里需要就是下 filterChainDefinitions 的value

      key 是 对应的跳转路径 这里都是指定的struts2的跳转 可以匹配通配符 *

      value 是对应的过滤权限 

        anon 不需要验证

        authc 需要登录验证

        roles[aa] 角色验证 中括号内为指定的角色

        perms[aaa] 权限验证 中括号内卫指定的权限

    4 添加shiro的缓存配置文件

    <ehcache>
        <diskStore path="java.io.tmpdir/shiro-spring-sample"/>
        <defaultCache
                maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                overflowToDisk="false"
                diskPersistent="false"
                diskExpiryThreadIntervalSeconds="120"
                />
    
        <cache name="shiro-activeSessionCache"
               maxElementsInMemory="10000"
               eternal="true"
               overflowToDisk="true"
               diskPersistent="true"
               diskExpiryThreadIntervalSeconds="600"/>
    
        <cache name="org.apache.shiro.realm.SimpleAccountRealm.authorization"
               maxElementsInMemory="100"
               eternal="false"
               timeToLiveSeconds="600"
               overflowToDisk="false"/>
    </ehcache>
    View Code

    5 角色 权限 实现

    因为只是一个demo  所以就没有弄角色表和权限表  只是模拟了一下 用户--角色--权限 的5表结构

     用户是查的表 角色和权限只是假实现

    6 修改 struts.xml

    <struts>
        <!-- 全局包设置 -->
        <package name="defalutGlobal" namespace="/" extends="json-default">
    
        </package>
        <!-- 自定义开发包 -->
        <package name="myDefault"  extends="defalutGlobal">
            <!--登录Action -->
            <action name="login_*" class="loginAction" method="{1}" >
                <result name="loginPage">WEB-INF/pages/login.html</result>
                <result name="loginPageForm">WEB-INF/pages/login2.html</result>
                <result name="home">WEB-INF/pages/home.html</result>
                <result name="hello">WEB-INF/pages/hello.html</result>
                
                <result name="success" type="json">
                    <param name="root">jsonResult</param>
                </result>
                
            </action>
    
            <action name="other_*" class="otherAction" method="{1}">
                <result name="error">WEB-INF/pages/other/error.html</result>
            </action>
        </package>    
            
        <package name="t1"  extends="defalutGlobal" namespace="/t1">
            <action name="t1_*" class="test1Action" method="{1}">
                <result name="t1">/WEB-INF/pages/t1/t1.html</result>
                <result name="t2">/WEB-INF/pages/t1/t2.html</result>
                <result name="t3">/WEB-INF/pages/t1/t3.html</result>
                <result name="toT2" type="redirect" >/t2/t2_t2.do</result>
                
            </action>
        </package>    
        <package name="t2"  extends="defalutGlobal" namespace="/t2">    
            <action name="t2_*" class="test2Action" method="{1}">
                <result name="t1">/WEB-INF/pages/t2/t1.html</result>
                <result name="t2">/WEB-INF/pages/t2/t2.html</result>
                <result name="t3">/WEB-INF/pages/t2/t3.html</result>
            </action>
        </package>    
        <package name="t3"  extends="defalutGlobal" namespace="/t3">    
            <action name="t3_*" class="test3Action" method="{1}">
                <result name="t1">/WEB-INF/pages/t3/t1.html</result>
                <result name="t2">/WEB-INF/pages/t3/t2.html</result>
                <result name="t3">/WEB-INF/pages/t3/t3.html</result>
            </action>
        </package>    
    
    </struts>

    这里为了更好地测试shiro的权限角色控制 所以把 t1,t2,t3加了namespace

    7 添加html

    这里就没啥说的了  给个缩略图吧

    8 实现reaml

    public class ShiroDbRealm extends AuthorizingRealm {
    
        @Autowired
        private UserService userService;
        @Autowired
        private RoleService roleService;
        @Autowired
        private PermissionService permissionService;
        
        /**
         * 认证回调函数,登录时调用.
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(
                AuthenticationToken authcToken) throws AuthenticationException {
            UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
            User user = userService.getByUserName(token.getUsername());
            if (user != null) {
                return new SimpleAuthenticationInfo(new ShiroUser(user.getUsername(), user.getNickname()), user.getPassword(),getName());
            } else {
                return null;
            }
        }
    
        /**
         * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(
                PrincipalCollection principals) {
            ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
            
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            // 加载用户的roles
            List<Role> roles = roleService.getByUserName(shiroUser.username);
            List<String> stringRoles = new ArrayList<String>(roles.size());
            for (Role role : roles) {
                stringRoles.add(role.getRolename());
            }
            info.addRoles(stringRoles);
            
            // 加载用户的permissions
            List<Permission> permissions = permissionService.getByUserName(shiroUser.username);
            Set<String> stringPermissions = new HashSet<String>(permissions.size());
            for (Permission permission : permissions) {
                stringPermissions.add(permission.getPermissionname());
            }
            info.setStringPermissions(stringPermissions);
            
            return info;
        }
        
        /**
         * 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息.
         */
        public static class ShiroUser implements Serializable {
            private static final long serialVersionUID = -1373760761780840081L;
            private String username;
            private String nickname;
    
            public ShiroUser(String username, String nickname) {
                this.username = username;
                this.nickname = nickname;
            }
        /**------getset略--------*/
        }
    }

    9 action

    public class LoginAction extends BaseAction{
        
        private String username;
        private String password;
        @Autowired
        UserService userService;
        
        /**
         * 登录页面
         */
        public String loginPage(){return "loginPage";
        }
        
        
        /**
         * home页面
         */
        public String home(){
            return "home";
        }
        
        /**
         * hello页面
         */
        public String hello(){
            System.out.println(SecurityUtils.getSubject().hasRole("cc"));
            return "hello";
        }
        
        
        /**
         * 登录
         */
        public String login(){
            Map<String,Object> map = new HashMap<String,Object>();
            User u=new User(getUsername(),getPassword());
            u=userService.check(u);
            if("0".equals(u.getRes())){
                map.put("res", "true");     
                AuthenticationToken token = new UsernamePasswordToken(username,password);// username和password是从表单提交过来的
                Subject currentUser = SecurityUtils.getSubject();
                currentUser.login(token);
                
            }else{
                map.put("res", "false");
            }
            JSONObject json = JSONObject.fromObject(map);//将map对象转换成json类型数据
            setJsonResult(json.toString());//给result赋值,传递给页面
            return "success";
        }
        
        /**
         * 登录页面
         */
        public String loginPageForm(){
            String result="loginPageForm";
            return result;
        }
        /**
         * 登录
         */
        public String loginForm(){
            System.out.println("loginForm");
            String result="loginPageForm";
            User u=new User(getUsername(),getPassword());
            u=userService.check(u);
            
            if("0".equals(u.getRes())){
                AuthenticationToken token = new UsernamePasswordToken(username,password);// username和password是从表单提交过来的
                Subject currentUser = SecurityUtils.getSubject();
                currentUser.login(token);
                result="home";
            }
            
            return result;
        }
        
        
        /**
         * 登出
         */
        public String logout(){
            Subject currentUser = SecurityUtils.getSubject();if (currentUser.isAuthenticated()) {
                currentUser.logout(); // session 会销毁,在SessionListener监听session销毁,清理权限缓存
                if (LOG.isDebugEnabled()) {
                    LOG.debug("用户" + username + "退出登录");
                }
            }return "loginPage";
        }
    
      /**--------getset略----------*/
    }

    这里就只上LoginAction了 其他的action 只是实现的跳转没有啥实际操作 就略过了

    如果先看其他action 就只能下源码了 

    这里还要说一下 登录页面写了两个 一个是ajax的一个是form 没有啥特别的 只是为了之后学习shiro remberme功能 打个提前量

    10 数据库结果

    create table base_user
    (
       id                   int not null auto_increment,
       createtime           char(20),
       username                char(20),
       password                char(20),
       nickname                char(20),
       t1                   char(100),
       t2                    char(30),
       primary key (id)
    );

    好 完成 测试下 成功

    最后总结下

    1 不得不吐槽下 网上的关于shiro的教程虽然不算少 但大都是 springMVC的 关于struts2的还是比较少的

    2 文档还是官方的好  放一个中文的shiro参考手册 下载

    3 本人研究shiro时间不长 这里只是作为一个入门参考 如果文中有错误的地方 尽情支出 欢迎技术喷子

    4 下次打算把shiro的 rememberme等功能研究下 再写一篇

    5 本项目 下载

  • 相关阅读:
    【.Net】多语言查看MSDN
    【.Net】 显示星期字符串
    【.Net】 判断时间字符串正确性
    【.Net】 实现窗口拖动
    【.Net】 Winform 单例运行实例
    Kendo 计算字段
    Kendo UI 的 k-template
    UpdatePanel中用后台CS代码调用JS代码,先执行控件事件,后触发JS
    SQL常用
    Node.js 安装
  • 原文地址:https://www.cnblogs.com/jethypc/p/5368304.html
Copyright © 2011-2022 走看看