• jeecmsv8 shiro 分析


     

    源代码注释可见 https://github.com/chenbo19867758/jeecmsV8-BoBo.git

    1.后台登录页面

    /jeeadmin/jeecms/login.do
    • 1

    web.xml中

    <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <init-param>
                <!--
                    targetFilterLifecycle 允许代理注入Spring bean
                    解决因为filter比bean先加载,也就是spring会先加载filter指定的类到container中,这样filter中注入的spring
                    bean就为null了 设置为true由servlet容器控制filter的生命周期
                -->
                <param-name>targetFilterLifecycle</param-name>
                <param-value>true</param-value>
            </init-param>
            <!--
                设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean 这里未设置 自动找到
                shiro-context.xml 中的 shiroFilter bean 过滤 <init-param>
                <param-name>targetBeanName</param-name>
                <param-value>shiroFilter</param-value> </init-param>
            -->
        </filter>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    shiro-context.xml 配置了

    /jeeadmin/jeecms/login.do = authc
    • 1

    请求登录时会进入自定义过滤器 authcFilter

    <bean id="authcFilter" class="com.jeecms.core.security.CmsAuthenticationFilter"
            parent="adminUrlBean">
            <!-- 登录成功后进入的页面 -->
            <property name="adminIndex" value="/jeeadmin/jeecms/index.do" />
        </bean>
    • 1
    • 2
    • 3
    • 4
    • 5

    CmsAuthenticationFilter 中

        public boolean onPreHandle(ServletRequest request,
                ServletResponse response, Object mappedValue) throws Exception {
            boolean isAllowed = isAccessAllowed(request, response, mappedValue);
            // 判断是否登录页面的请求,转向登录页面
            if (isAllowed && isLoginRequest(request, response)) {
                try {
                    issueSuccessRedirect(request, response);
                } catch (Exception e) {
                    logger.error("", e);
                }
                return false;
            }
            return isAllowed || onAccessDenied(request, response, mappedValue);
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
        /**
         * 在这返回成功页面successUrl
         */
        protected void issueSuccessRedirect(ServletRequest request, ServletResponse response)
                throws Exception {
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse res = (HttpServletResponse) response;
            String successUrl = req.getParameter(RETURN_URL);
            if (StringUtils.isBlank(successUrl)) {
                if (req.getRequestURI().startsWith(
                        req.getContextPath() + getAdminPrefix())) {
                    // 后台直接返回首页,这里为 /jeeadmin/jeecms/index.do
                    successUrl = getAdminIndex();
                    // 清除SavedRequest
                    WebUtils.getAndClearSavedRequest(request);
                    WebUtils.issueRedirect(request, response, successUrl, null,true);
                    return;
                } else {
                    // 返回默认的成功页,AuthenticationFilter 中 DEFAULT_SUCCESS_URL = "/";
                    successUrl = getSuccessUrl();
                }
            }
            WebUtils.getAndClearSavedRequest(request);
            WebUtils.issueRedirect(request, response, successUrl, null,true);
            //WebUtils.redirectToSavedRequest(req, res, successUrl);
        }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    判断是否登录页面的请求, 登录页面转向的成功页面,并区分前端登录和后端登录

    登录失败则跳转到spring mvc 映射的路径, CmsLoginAct 中

    // 登录失败转向这里
        // submit 名称不是固定的随便取, 只需匹配 @RequestMapping
        @RequestMapping(value = "/login.do", method = RequestMethod.POST)
        public String submit(String username, HttpServletRequest request,
                HttpServletResponse response, ModelMap model) {
            Object error = request.getAttribute(DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
            if (error != null) {
                model.addAttribute("error", error);
                Integer errorRemaining= unifiedUserMng.errorRemaining(username);
                model.addAttribute("errorRemaining", errorRemaining);
            }
            //此方法不处理登陆成功(认证成功),shiro认证成功会自动跳转到上一个请求路径
            //登陆失败还到login页面
            return "login";
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    shiro详解

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"
        default-lazy-init="true">
    
        <!-- web.xml中 对应名称 <filter-name>shiroFilter</filter-name> -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <!-- Shiro的核心安全接口,这个属性是必须的 -->
            <property name="securityManager" ref="securityManager" />
            <!-- /login.jspx 前端用户登录地址 -->
            <property name="loginUrl" value="/login.jspx" />
            <!-- successUrl认证成功统一跳转地址,不配置,shiro认证成功自动到上一个请求路径 -->
            <property name="successUrl" value="/" />
    
            <!-- 
                这是因为shiro源代码中判断了filter是否为AuthorizationFilter,
                只有perms,roles,ssl,rest,port才是属于AuthorizationFilter(授权),
                而anon,authcBasic,auchc,user是AuthenticationFilter(验证),所以unauthorizedUrl(未被授权的url)设置后不起作用。
                这里不需要配置 unauthorizedUrl
             -->
    
            <!-- 自定义filter配置 -->
            <property name="filters">
                <util:map>
                    <!-- 下面配置 authcFilter bean -->
                    <entry key="authc" value-ref="authcFilter" />
                    <!-- 下面配置 userFilter bean -->
                    <entry key="user" value-ref="userFilter" />
                    <!--  退出过滤器, 下面配置 logoutFilter bean -->
                    <entry key="logout" value-ref="logoutFilter" />
                </util:map>
            </property>
            <!--
                anon匿名 authc登录认证 user用户已登录 logout退出filter anon:例子/admins/**=anon
                没有参数,表示可以匿名使用。 authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数
                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认证
                ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
    
                user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
                user是介于,anon和authc直之间的。换句话来说:而“/authenticated=
                user”表示访问该地址的用户是身份验证通过或RememberMe
                登录的都可以。或者说,某个页面需要登录才能看,但这个页面信息又不太重要,就可已使用这个
            -->
            <!--
                后台首页登录 /jeeadmin/jeecms/login.do 后台登录页面访问的接口
                /jeeadmin/jeecms/login.do = authc 配置为需要验证权限登录 需要过来器<entry key="authc"
                value-ref="authcFilter" /> 过滤
            -->
            <!-- 
                filterChainDefinitions Shiro连接约束配置,即过滤链的定义
                Shiro Filter的执行顺序 “ 自上而下,从左到右”
            -->  
            <property name="filterChainDefinitions">
                <value>
                    *.jspx = anon
                    *.jhtml = anon
                    /member/forgot_password.jspx = anon
                    /member/password_reset.jspx = anon
                    /member/jobapply.jspx = anon
                    /login.jspx = authc
                    /logout.jspx = logout
                    /member/** = user
                    /jeeadmin/jeecms/login.do = authc
                    /jeeadmin/jeecms/logout.do = logout
                    /jeeadmin/jeecms/** =user
                </value>
            </property>
        </bean>
        <!-- Shiro Filter -->
        <!-- 全局定义adminLogin,adminPrefix 供下面的bean使用 -->
        <bean id="adminUrlBean" class="com.jeecms.core.security.CmsAdminUrl">
            <property name="adminLogin" value="/jeeadmin/jeecms/login.do" />
            <property name="adminPrefix" value="/jeeadmin/jeecms/" />
        </bean>
        <!-- 
            自定义过滤
            parent="adminUrlBean" 继承adminUrlBean 注入的属性 
         -->
        <bean id="authcFilter" class="com.jeecms.core.security.CmsAuthenticationFilter"
            parent="adminUrlBean">
            <!-- 登录成功后进入的页面 -->
            <property name="adminIndex" value="/jeeadmin/jeecms/index.do" />
        </bean>
    
        <!--
            <entry key="user" value-ref="userFilter" /> 配置过滤 user 权限的访问地址
            /member/** = user /jeeadmin/jeecms/** =user
        -->
        <bean id="userFilter" class="com.jeecms.core.security.CmsUserFilter"
            parent="adminUrlBean" />
    
        <!-- 退出过滤器 -->
        <bean id="logoutFilter" class="com.jeecms.core.security.CmsLogoutFilter"
            parent="adminUrlBean" />
    
        <!-- 核心管理类 入口, security 安全,-->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="cacheManager" ref="shiroEhcacheManager" />
            <property name="rememberMeManager" ref="rememberMeManager" />
            <property name="realm" ref="authorizingRealm" /> <!-- 凭证匹配器 -->
        </bean>
        <!-- 凭证匹配器,核心验证登录与权限授权 -->
        <bean id="authorizingRealm" class="com.jeecms.core.security.CmsAuthorizingRealm">
            <property name="credentialsMatcher">
                <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                    <!-- 加密的方式,MD5 -->
                    <property name="hashAlgorithmName" value="MD5" />
                    <!--   true means hex encoded, false means base64 encoded -->
                    <property name="storedCredentialsHexEncoded" value="true" />
                    <!-- 迭代次数,散列的次数 ,加密的次数,2的话就是加密后把加密的值再加密一次 -->
                    <property name="hashIterations" value="1" />
                </bean>
            </property>
            <property name="cmsUserMng" ref="cmsUserMng" />
        </bean>
        <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
            <!--
                <property name="cacheManagerConfigFile">
                <value>classpath:ehcache-shiro.xml</value> </property>
            -->
            <property name="cacheManager">
                <ref local="cacheManager" />
            </property>
        </bean>
        <!-- 会话Cookie模板 -->  
        <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
            <!-- 
                constructor-arg 构造器注入
                前端登录或后端登录,可以传入rememberMe 参数实现记住我功能
                rememberMe是cookie的名字  
            --> 
            <constructor-arg value="rememberMe" /> 
            <property name="httpOnly" value="true" />
            <property name="maxAge" value="31536000" /><!-- 365天 -->
        </bean>
        <!-- 
            rememberMe管理器
            cipherKey是加密rememberMe Cookie的密钥;默认AES算法;
         -->
        <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
            <property name="cipherKey"
                value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}" />
            <property name="cookie" ref="rememberMeCookie" />
        </bean>
        <!--
            Enable Shiro Annotations for Spring-configured beans. Only run after
        -->
        <!-- 
            the lifecycleBeanProcessor has run: 
            jeecms-servlet-admin.xml中配置使用
    
            lifecycleBeanPostProcessor Shiro生命周期处理器
            LifecycleBeanPostProcessor用于在实现了Initializable接口的Shiro bean初始化时调用Initializable接口回调,
            在实现了Destroyable接口的Shiro bean销毁时调用 Destroyable接口回调。
            如UserRealm就实现了Initializable,
            而DefaultSecurityManager实现了Destroyable。
        -->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
    </beans>
  • 相关阅读:
    洛谷1026 统计单词个数
    洛谷1381 单词背诵
    Manacher(hdu3068最长回文)
    洛谷P1078 文化之旅
    HDU1269 迷宫城堡
    codevs1020 孪生蜘蛛
    洛谷P1027 Car的旅行路线
    楼房 洛谷1382 && codevs2995
    Picture poj1177
    排列组合
  • 原文地址:https://www.cnblogs.com/Jeely/p/11214558.html
Copyright © 2020-2023  润新知