zoukankan      html  css  js  c++  java
  • apache shiro整合spring(一)

    apache shiro整合spring

    maven引入jar包

    <dependency>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-all</artifactId>
         <version>1.2.3</version>
    </dependency>

    将shiro配置文件整合到spring体系中

    方式一:直接在spring的配置文件中import shiro的配置文件

    web.xml中配置spring

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

    在spring配置文件中引入shiro配置文件

    <import resource="applicationContext-shiro.xml"/>
     

    方式二:直接在web.xml中配置shiro的配置文件

    <!-- Spring ApplicationContext 配置文件的路径,可使用通配符,多个路径用,号分隔 此参数用于后面的Spring Context Loader -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:/applicationContext-shiro.xml</param-value>
    </context-param>
    <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
     

    在web.xml中定义shiro的过滤器

        <!-- 这里的filter-name 要和spring 的applicationContext-shiro.xml 里的
    org.apache.shiro.spring.web.ShiroFilterFactoryBean 的bean name 相同 -->
        <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>
        </filter-mapping>
     

    1.shiro中定义的filtername bean是要被wen.xml引用的,所以这里的filtername要和shiro中的filtername相同 
    2.shiro的filter要定义在Struts2的filter之前,否则action无法创建

    shiro.xml配置文件(配置校验的策略,哪些校验,哪些放行)

        <!-- 安全管理 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <!-- Single realm app.  If you have multiple realms, use the 'realms' property instead. -->
            <property name="realm" ref="authRealm"/><!-- 引用自定义的realm -->
            <!-- 二级缓存 -->
            <property name="cacheManager" ref="shiroEhcacheManager"/>
        </bean>
    
        <!-- 自定义权限认证 -->
        <bean id="authRealm" class="com.fyh.www.shiro.AuthRealm">
    <!--        <property name="userService" ref="userService"/> -->
            <!-- 自定义密码加密算法  -->
            <property name="credentialsMatcher" ref="passwordMatcher"/>
        </bean>
    
        <!-- 设置密码加密策略 md5hash -->
        <bean id="passwordMatcher" class="com.fyh.www.shiro.CustomCredentialsMatcher"/>
    
        <!-- 此bean要被web.xml引用,和web.xml中的filtername同名 -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager"/>
            <property name="loginUrl" value="/index.jsp" /> <!-- 没有认证返回地址 -->
            <property name="unauthorizedUrl" value="/index2.jsp" /> <!-- 没有授权返回地址 -->
            <property name="filterChainDefinitions">
                <value>            <!-- **代表任意子目录 -->
                /login/** = anon
                /user/** = authc,roles[admin]
                /test/** = authc,perms[测试用的lkkk]
                </value>
            </property>
        </bean>
    
        <!-- 用户授权/认证信息Cache, 采用EhCache  缓存 -->
        <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
            <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
        </bean>
    
        <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    
        <!-- 生成代理,通过代理进行控制 -->
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
              depends-on="lifecycleBeanPostProcessor">
        </bean>
    
        <!-- 安全管理器 -->
        <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="securityManager" ref="securityManager"/>
        </bean>

    shiro缓存(ehcache支持ehcache-shiro.xml)

    Alt text

    <ehcache updateCheck="false" name="shiroCache">
    
        <defaultCache
                maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                overflowToDisk="false"
                diskPersistent="false"
                diskExpiryThreadIntervalSeconds="120"
                />
    </ehcache>
     

    java代码实现

    自定义密码认证

    public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {
        public boolean doCredentialsMatch(AuthenticationToken token,
                AuthenticationInfo info) {
            UsernamePasswordToken usertoken = (UsernamePasswordToken) token; 
    
            //注意token.getPassword()拿到的是一个char[],不能直接用toString(),它底层实现不是我们想的直接字符串,只能强转
            Object tokenCredentials = Encrypt.md5(String.valueOf(usertoken.getPassword()),usertoken.getUsername());  
            Object accountCredentials = getCredentials(info);  
    
            //将密码加密与系统加密后的密码校验,内容一致就返回true,不一致就返回false  
            return equals(tokenCredentials, accountCredentials);  
        }
    }


    util中定义shiro的MD5加密方法

    public class Encrypt {
        /*
         * 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,
         * 常见的散列算法如MD5、SHA等。一般进行散列时最好提供一个salt(盐),比如加密密码“admin”,
         * 产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,
         * 可以到一些md5解密网站很容易的通过散列值得到密码“admin”,
         * 即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,
         * 如用户名和ID(即盐);这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解。
         */
    
        //高强度加密算法,不可逆
        public static String md5(String password, String salt){
            return new Md5Hash(password,salt,2).toString();
        }
    
        public static void main(String[] args) {
            System.out.println(new Md5Hash("123456","tony",2).toString());
        }
    
    
    }
     

    自定义realm AuthRealm

    在认证、授权内部实现机制中都有提到,最终处理都将交给Realm进行处理。 
    因为在Shiro中,最终是通过Realm来获取应用程序中的用户、角色及权限信息的。 
    通常情况下,在Realm中会直接从我们的数据源中获取Shiro需要的验证信息。可以说,Realm是专用于安全框架的DAO.

     
    public class AuthRealm extends AuthorizingRealm{
        private UserService userService;
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
    
        //授权
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            System.out.println("授权");
            //获取当前用户
            User user = (User)principals.fromRealm(getName()).iterator().next();
            //得到权限字符串
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
            Set<Role> roles = user.getRoles();
            List<String> list = new ArrayList();
            for(Role role :roles){
                Set<Module> modules = role.getModules();
                for(Module m:modules){
                    if(m.getCtype()==0){
                        //说明是主菜单
                        list.add(m.getCpermission());
                    }
                }
            }
    
            info.addStringPermissions(list);
            return info;
        }
        //认证  登录
        protected AuthenticationInfo doGetAuthenticationInfo(
                AuthenticationToken token) throws AuthenticationException {
            System.out.println("认证");
            UsernamePasswordToken upToken = (UsernamePasswordToken)token;
    
            User user = userService.findUserByName(upToken.getUsername());
            if(user==null){
                return null;
            }else{
                AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
                return info;
            }
    
        }
    
    }
     

    修改传统登录为shiro登录

    public class LoginAction extends BaseAction {
    
        private static final long serialVersionUID = 1L;
    
        private String username;
        private String password;
    
        private UserService userService;
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
    
        public String login() throws Exception {    
            /*
             * shiro登录方式:根据用户名获取密码,密码为null非法用户;有密码检查是否用户填写的密码
             * 登录成功后无需往httpsession中存放当前用户,这样就跟web容器绑定,关联太紧密;它自己创建
             * subject对象,实现自己的session。这个跟web容器脱离,实现松耦合。
             */
    
            //调用shiro判断当前用户是否是系统用户
            Subject subject = SecurityUtils.getSubject();   //得到当前用户
            //shiro是将用户录入的登录名和密码(未加密)封装到token对象中
            UsernamePasswordToken token = new UsernamePasswordToken(userName,password);
    
            try{
                subject.login(token);   //自动调用AuthRealm.doGetAuthenticationInfo
    
                //写seesion,保存当前user对象
                User curUser = (User)subject.getPrincipal();            //从shiro中获取当前用户
                System.out.println(curUser.getDept().getDeptName());    //让懒加载变成立即加载
                Set<Role> roles = curUser.getRoles();
                for(Role role :roles){
                    Set<Module> moduless =  role.getModules();
                    for(Module m :moduless)
                       System.out.println(m.getName());
                }
                session.put(SysConstant.CURRENT_USER_INFO, curUser);    //Principal 当前用户对象
            }catch(Exception ex){
                super.put("errorInfo","用户名密码错误,请重新填写!");
                ex.printStackTrace();
    
                return "login";
            }
            return SUCCESS;
        }
    
        public String logout(){
            session.remove(SysConstant.CURRENT_USER_INFO);      //删除session
            return "logout";
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
    }
     

    页面使用shiro标签

    <%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro"%>
    
            <shiro:hasPermission name="sysadmin">
            <span id="topmenu" onclick="toModule('sysadmin');">系统管理</span>
            </shiro:hasPermission>
     
  • 相关阅读:
    Netty(一、初步了解)
    nginx(三、keepalived高可用)
    nginx(二、配置文件)
    nginx(一、安装与启动)
    ElasticSeach(六、springboot集成ES high level client)
    ElasticSeach(五、命令操作)
    ElasticSeach(四、mapping)
    ElasticSeach(三、IK分词器配置)
    ElasticSeach(二、部署运行)
    ElasticSeach(一、基本概念)
  • 原文地址:https://www.cnblogs.com/woms/p/5992795.html
Copyright © 2011-2022 走看看