zoukankan      html  css  js  c++  java
  • spring结合shiro的学习总结

    pom文件加入

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

    web.xml

        <!-- 配置Shiro过滤器,先让Shiro过滤系统接收到的请求 -->
        <!-- 这里filter-name必须对应applicationContext.xml中定义的<bean id="shiroFilter"/> -->
        <!-- 使用[/*]匹配所有请求,保证所有的可控请求都经过Shiro的过滤 -->
        <!-- 通常会将此filter-mapping放置到最前面(即其他filter-mapping前面),以保证它是过滤器链中第一个起作用的 -->
        <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <init-param>
                <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由servlet container管理 -->
                <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>
    

    spring.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="
            http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">
    
    	<!-- 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的UserRealm.java -->  
    	<bean id="userRealm" class="com.platform.shiro.UserRealm"/>
    
        <bean id="cluterShiroSessionDao" class="com.platform.shiro.CluterShiroSessionDao"/>
    
    	<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    		<!-- 设置session过期时间为1小时(单位:毫秒),默认为30分钟 -->
    		<property name="globalSessionTimeout" value="3600000"></property>
    		<property name="sessionValidationSchedulerEnabled" value="true"></property>
    		<property name="sessionIdUrlRewritingEnabled" value="false"></property>
            <property name="sessionDAO" ref="cluterShiroSessionDao"/>
    	</bean>
    	
    	<!-- Shiro默认会使用Servlet容器的Session,可通过sessionMode属性来指定使用Shiro原生Session -->  
    	<!-- 即<property name="sessionMode" value="native"/>,详细说明见官方文档 -->  
    	<!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替 -->  
    	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    		<property name="sessionManager" ref="sessionManager"></property>
    	    <property name="realm" ref="userRealm"/>
    	</bean>
    
    	<!-- Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行 -->
    	<!-- Web应用中,Shiro可控制的Web请求必须经过Shiro主过滤器的拦截,Shiro对基于Spring的Web应用提供了完美的支持 -->
    	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
    	    <!-- Shiro的核心安全接口,这个属性是必须的 -->  
    	    <property name="securityManager" ref="securityManager"/>  
    	    <!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.html"页面 -->  
    	    <property name="loginUrl" value="/login.html"/>  
    	    <!-- 登录成功后要跳转的连接 -->  
    	    <property name="successUrl" value="/index.html"/>
    	    <!-- 用户访问未对其授权的资源时,所显示的连接 -->  
    	    <!-- 若想更明显的测试此属性可以修改它的值,如unauthor.jsp,然后用[玄玉]登录后访问/admin/listUser.jsp就看见浏览器会显示unauthor.jsp -->  
    	    <property name="unauthorizedUrl" value="/"/>  
    	    <!-- Shiro连接约束配置,即过滤链的定义 -->  
    	    <!-- 此处可配合我的这篇文章来理解各个过滤连的作用http://blog.csdn.net/jadyer/article/details/12172839 -->  
    	    <!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的 -->  
    	    <!-- anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 -->  
    	    <!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->  
    	    <property name="filterChainDefinitions">  
    	        <value>
    	        	/statics/**=anon
    				/api/**=anon
    				/api/**=noSessionCreation
    	        	/login.html=anon
    	        	/sys/login=anon
    	        	/captcha.jpg=anon
    	        	/**=authc
    	        </value>
    	    </property>
    	</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>
    

     

    UserRealm.java
    public class UserRealm extends AuthorizingRealm {
        @Autowired
        private SysUserDao sysUserDao;
        @Autowired
        private SysMenuDao sysMenuDao;
    
        /**
         * 授权(验证权限时调用)
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            SysUserEntity user = (SysUserEntity) principals.getPrimaryPrincipal();
            Long userId = user.getUserId();
    
            List<String> permsList;
    
            //系统管理员,拥有最高权限
            if (userId == Constant.SUPER_ADMIN) {
                List<SysMenuEntity> menuList = sysMenuDao.queryList(new HashMap<>());
                permsList = new ArrayList<>(menuList.size());
                for (SysMenuEntity menu : menuList) {
                    permsList.add(menu.getPerms());
                }
            } else {
                permsList = sysUserDao.queryAllPerms(userId);
            }
            //用户权限列表
            Set<String> permsSet = new HashSet<String>();
            if (permsList != null && permsList.size() != 0) {
                for (String perms : permsList) {
                    if (StringUtils.isBlank(perms)) {
                        continue;
                    }
                    permsSet.addAll(Arrays.asList(perms.trim().split(",")));
                }
            }
    
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.setStringPermissions(permsSet);
            return info;
        }
    
        /**
         * 认证(登录时调用)
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(
                AuthenticationToken token) throws AuthenticationException {
            String username = (String) token.getPrincipal();
            String password = new String((char[]) token.getCredentials());
    
            //查询用户信息
            SysUserEntity user = sysUserDao.queryByUserName(username);
    
            //账号不存在
            if (user == null) {
                throw new UnknownAccountException("账号或密码不正确");
            }
    
            //密码错误
            if (!password.equals(user.getPassword())) {
                throw new IncorrectCredentialsException("账号或密码不正确");
            }
    
            //账号锁定
            if (user.getStatus() == 0) {
                throw new LockedAccountException("账号已被锁定,请联系管理员");
            }
    
            // 把当前用户放入到session中
            Subject subject = SecurityUtils.getSubject();
            Session session = subject.getSession(true);
            session.setAttribute(Constant.CURRENT_USER, user);
    
            List<String> permsList;
    
            //系统管理员,拥有最高权限
            if (Constant.SUPER_ADMIN == user.getUserId()) {
                List<SysMenuEntity> menuList = sysMenuDao.queryList(new HashMap<String, Object>());
                permsList = new ArrayList<>(menuList.size());
                for (SysMenuEntity menu : menuList) {
                    permsList.add(menu.getPerms());
                }
            } else {
                permsList = sysUserDao.queryAllPerms(user.getUserId());
            }
            J2CacheUtils.put(Constant.PERMS_LIST + user.getUserId(), permsList);
    
            //如果身份认证验证成功,返回一个AuthenticationInfo实现;
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
            return info;
        }
    
    }
    

      

     

    1、UserRealm父类AuthorizingRealm将获取Subject相关信息分成两步:获取身份验证信息(doGetAuthenticationInfo)及授权信息(doGetAuthorizationInfo);

    2、doGetAuthenticationInfo获取身份验证相关信息:首先根据传入的用户名获取User信息;然后如果user为空,那么抛出没找到帐号异常UnknownAccountException;如果user找到但锁定了抛出锁定异常LockedAccountException;最后生成AuthenticationInfo信息,交给间接父类AuthenticatingRealm使用CredentialsMatcher进行判断密码是否匹配,如果不匹配将抛出密码错误异常IncorrectCredentialsException;另外如果密码重试此处太多将抛出超出重试次数异常ExcessiveAttemptsException;在组装SimpleAuthenticationInfo信息时,需要传入:身份信息(用户名)、凭据(密文密码)、盐(username+salt),CredentialsMatcher使用盐加密传入的明文密码和此处的密文密码进行匹配。

    3、doGetAuthorizationInfo获取授权信息:PrincipalCollection是一个身份集合,因为我们现在就一个Realm,所以直接调用getPrimaryPrincipal得到之前传入的用户名即可;然后根据用户名调用UserService接口获取角色及权限信息。

      

  • 相关阅读:
    BZOJ 3205 [Apio2013]机器人 ——斯坦纳树
    BZOJ 3782 上学路线 ——动态规划 Lucas定理 中国剩余定理
    HDU 1423 Greatest Common Increasing Subsequence ——动态规划
    BZOJ 3309 DZY Loves Math ——莫比乌斯反演
    POJ 1038 Bugs Integrated, Inc. ——状压DP
    POJ 3693 Maximum repetition substring ——后缀数组
    POJ 2699 The Maximum Number of Strong Kings ——网络流
    POJ 2396 Budget ——有上下界的网络流
    BZOJ 4650 [Noi2016]优秀的拆分 ——后缀数组
    源码安装python
  • 原文地址:https://www.cnblogs.com/zqyanywn/p/10839687.html
Copyright © 2011-2022 走看看