美文网首页Shiro
Shiro实现后台和前端共用

Shiro实现后台和前端共用

作者: 发光的鱼 | 来源:发表于2017-07-05 16:56 被阅读597次

    1.近期在弄shiro的安全框架,目前情况是后端使用form请求进行登录,前端使用ajax进行登录。一是为减少重复代码编写,二是为了深入了解shiro的一些知识。

    2.后端框架使用ssm + shiro1.2.3,缓存方面主要用ehcache2.6.11或者redis,主要的shiro pom依赖有如下:

     <properties>
                <shiro.version>1.2.3</shiro.version>
     </properties>
    <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>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-cas</artifactId>
                <version>${shiro.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>commons-logging</groupId>
                        <artifactId>commons-logging</artifactId>
                    </exclusion>
                </exclusions>
            </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>
    

    3.spring配置shiro

    <!-- Shiro权限过滤过滤器定义 -->
        <bean name="shiroFilterChainDefinitions" class="java.lang.String">
            <constructor-arg>
                <value>
                    /open/smartFactory/** = authc
                    /weixin/** = anon
                    /static/** = anon
                    /userfiles/** = anon
                    ${adminPath}/cas = cas
                    ${adminPath}/login = authc
                    ${adminPath}/logout = logout
                    ${adminPath}/** = user
                    /act/editor/** = user
                    /ReportServer/** = user
                </value>
            </constructor-arg>
        </bean>
        
        <!-- 安全认证过滤器 -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />
            <property name="loginUrl" value="${adminPath}/login" />
            <property name="successUrl" value="${adminPath}?login" />
            <property name="filters">
                <map>
                    <entry key="cas" value-ref="casFilter"/>
                    <entry key="authc" value-ref="formAuthenticationFilter"/>
                </map>
            </property>
            <property name="filterChainDefinitions">
                <ref bean="shiroFilterChainDefinitions"/>
            </property>
        </bean>
        
        <!-- CAS认证过滤器 -->  
        <bean id="casFilter" class="org.apache.shiro.cas.CasFilter">  
            <property name="failureUrl" value="${adminPath}/login"/>
        </bean>
        
        <!-- 定义Shiro安全管理配置 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="systemAuthorizingRealm" />
            <property name="sessionManager" ref="sessionManager" />
            <property name="cacheManager" ref="shiroCacheManager" />
        </bean>
        
        <!-- 自定义会话管理配置 -->
        <bean id="sessionManager" class="com.thinkgem.jeesite.common.security.shiro.session.SessionManager"> 
            <property name="sessionDAO" ref="sessionDAO"/>
            
            <!-- 会话超时时间,单位:毫秒  -->
            <property name="globalSessionTimeout" value="${session.sessionTimeout}"/>
            
            <!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话   -->
            <property name="sessionValidationInterval" value="${session.sessionTimeoutClean}"/>
    <!--        <property name="sessionValidationSchedulerEnabled" value="false"/> -->
            <property name="sessionValidationSchedulerEnabled" value="true"/>
            
            <property name="sessionIdCookie" ref="sessionIdCookie"/>
            <property name="sessionIdCookieEnabled" value="true"/>
        </bean>
        
        <!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,
            当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! -->
        <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
            <constructor-arg name="name" value="jeesite.session.id"/>
        </bean>
    
        <!-- 自定义Session存储容器 -->
    <!--    <bean id="sessionDAO" class="com.thinkgem.jeesite.common.security.shiro.session.JedisSessionDAO"> -->
    <!--        <property name="sessionIdGenerator" ref="idGen" /> -->
    <!--        <property name="sessionKeyPrefix" value="${redis.keyPrefix}_session_" /> -->
    <!--    </bean> -->
        <bean id="sessionDAO" class="com.thinkgem.jeesite.common.security.shiro.session.CacheSessionDAO">
            <property name="sessionIdGenerator" ref="idGen" />
            <property name="activeSessionsCacheName" value="activeSessionsCache" />
            <property name="cacheManager" ref="shiroCacheManager" />
        </bean>
        
        <!-- 自定义系统缓存管理器-->
    <!--    <bean id="shiroCacheManager" class="com.thinkgem.jeesite.common.security.shiro.cache.JedisCacheManager"> -->
    <!--        <property name="cacheKeyPrefix" value="${redis.keyPrefix}_cache_" /> -->
    <!--    </bean> -->
        <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
            <property name="cacheManager" ref="cacheManager"/>
        </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>
    

    4.shiro的登录

    @Service
    public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(FormAuthenticationFilter.class);
    
        public static final String DEFAULT_CAPTCHA_PARAM = "validateCode";
        public static final String DEFAULT_MOBILE_PARAM = "mobileLogin";
        public static final String DEFAULT_MESSAGE_PARAM = "message";
    
        private String captchaParam = DEFAULT_CAPTCHA_PARAM;
        private String mobileLoginParam = DEFAULT_MOBILE_PARAM;
        private String messageParam = DEFAULT_MESSAGE_PARAM;
    
        protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
            String username = getUsername(request);
            String password = getPassword(request);
            if (password == null) {
                password = "";
            }
            boolean rememberMe = isRememberMe(request);
            String host = StringUtils.getRemoteAddr((HttpServletRequest) request);
            String captcha = getCaptcha(request);
            boolean mobile = isMobileLogin(request);
            return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha, mobile);
        }
    
        /**
         * 每次请求的时候都先进入此方法
         *
         * @param request
         * @param response
         * @return
         * @throws Exception
         */
        @Override
        protected boolean onAccessDenied(ServletRequest request,
                                         ServletResponse response) throws Exception {
            HttpServletResponse resp = (HttpServletResponse) response;
            HttpServletRequest resq = (HttpServletRequest) request;
            // 后台form
            if (isLoginRequest(request, response)) {
                if (isLoginSubmission(request, response)) {
                    return executeLogin(request, response);
                } else {
                    return true;
                }
            } else {
                // ajax请求
                if ("XMLHttpRequest"
                        .equalsIgnoreCase(((HttpServletRequest) request)
                                .getHeader("X-Requested-With"))) {
                    saveRequestAndRedirectToLogin(request, response);
                } else {
                    request.setCharacterEncoding("utf-8");
                    resp.setHeader("Content-type", "text/html;charset=UTF-8");
                    resp.setCharacterEncoding("utf-8");
    
                    Result result = ResultGenerator.getNotLoginResult(
                            new String("没有登录,请登录".getBytes(), "UTF-8"));
                    resp.getWriter().write(JSON.toJSONString(result));
                    resp.getWriter().flush();
                    resp.getWriter().close();
                }
                return false;
            }
        }
    
        /**
         * 获取登录用户名
         */
    
        protected String getUsername(ServletRequest request, ServletResponse response) {
            String username = super.getUsername(request);
            if (StringUtils.isBlank(username)) {
                username = StringUtils.toString(request.getAttribute(getUsernameParam()), StringUtils.EMPTY);
            }
            return username;
        }
    
        /**
         * 获取登录密码
         */
        @Override
        protected String getPassword(ServletRequest request) {
            String password = super.getPassword(request);
            if (StringUtils.isBlank(password)) {
                password = StringUtils.toString(request.getAttribute(getPasswordParam()), StringUtils.EMPTY);
            }
            return password;
        }
    
        /**
         * 获取记住我
         */
        @Override
        protected boolean isRememberMe(ServletRequest request) {
            String isRememberMe = WebUtils.getCleanParam(request, getRememberMeParam());
            if (StringUtils.isBlank(isRememberMe)) {
                isRememberMe = StringUtils.toString(request.getAttribute(getRememberMeParam()), StringUtils.EMPTY);
            }
            return StringUtils.toBoolean(isRememberMe);
        }
    
        public String getCaptchaParam() {
            return captchaParam;
        }
    
        protected String getCaptcha(ServletRequest request) {
            return WebUtils.getCleanParam(request, getCaptchaParam());
        }
    
        public String getMobileLoginParam() {
            return mobileLoginParam;
        }
    
        protected boolean isMobileLogin(ServletRequest request) {
            return WebUtils.isTrue(request, getMobileLoginParam());
        }
    
        public String getMessageParam() {
            return messageParam;
        }
    
        /**
         * 登录成功之后跳转URL
         */
        public String getSuccessUrl() {
            return super.getSuccessUrl();
        }
    
        @Override
        protected void issueSuccessRedirect(ServletRequest request,
                                            ServletResponse response) throws Exception {
            SystemAuthorizingRealm.Principal p = UserUtils.getPrincipal();
            if (p != null && !p.isMobileLogin()) {
                WebUtils.issueRedirect(request, response, getSuccessUrl(), null, true);
            }
    //        else {
    //            super.issueSuccessRedirect(request, response);
    //        }
        }
    
    
        /**
         * 登录成功回调
         *
         * @param token
         * @param subject
         * @param request
         * @param response
         * @return
         * @throws Exception
         */
        @Override
        protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
            HttpServletRequest resq = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            // 返回ajax数据
            if (!isBackground(request)) {
                request.setCharacterEncoding("utf-8");
                resp.setHeader("Content-type", "text/html;charset=UTF-8");
                resp.setCharacterEncoding("utf-8");
                String tokenId = (String) UserUtils.getSession().getId();
                Map tokenMap = Maps.newHashMapWithExpectedSize(1);
                tokenMap.put(Global.TOKEN, tokenId);
                Result result = ResultGenerator.getSuccessResult(tokenMap);
                response.getWriter().write(JSON.toJSONString(result));
                response.getWriter().flush();
                response.getWriter().close();
            } else {
                // modelandview方式
                issueSuccessRedirect(request, response);
            }
            return false;
        }
    
        /**
         * 登录失败调用事件
         */
        @Override
        protected boolean onLoginFailure(AuthenticationToken token,
                                         AuthenticationException e, ServletRequest request, ServletResponse response) {
            HttpServletResponse resp = (HttpServletResponse) response;
            String className = e.getClass().getName(), message = "";
    
            // 返回json格式信息
    
            if (IncorrectCredentialsException.class.getName().equals(className)
                    || UnknownAccountException.class.getName().equals(className)) {
                message = "用户或密码错误, 请重试.";
            } else if (e.getMessage() != null && StringUtils.startsWith(e.getMessage(), "msg:")) {
                message = StringUtils.replace(e.getMessage(), "msg:", "");
            } else {
                message = "系统出现点问题,请稍后再试!";
                e.printStackTrace(); // 输出到控制台
            }
            Result result = ResultGenerator.getFailResult(message);
    
            // 返回ajax信息
            if (!isBackground(request)) {
                try {
                    request.setCharacterEncoding("utf-8");
                    resp.setHeader("Content-type", "text/html;charset=UTF-8");
                    resp.setCharacterEncoding("utf-8");
                    response.getWriter().write(JSON.toJSONString(result));
                    response.getWriter().flush();
                    response.getWriter().close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            } else {
                request.setAttribute(getFailureKeyAttribute(), className);
                request.setAttribute(getMessageParam(), message);
            }
            return true;
        }
    
    
        private boolean isBackground(ServletRequest request) {
            if ("XMLHttpRequest"
                    .equalsIgnoreCase(((HttpServletRequest) request)
                            .getHeader("X-Requested-With"))) {
                return true;
            }
            return false;
        }
    }
    

    5.系统的认证实现类

    @Service
    //@DependsOn({"userDao","roleDao","menuDao"})
    public class SystemAuthorizingRealm extends AuthorizingRealm {
    
        private Logger logger = LoggerFactory.getLogger(getClass());
        
        private SystemService systemService;
        
        public SystemAuthorizingRealm() {
            this.setCachingEnabled(false);
        }
    
        @Override
        protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
            super.assertCredentialsMatch(token, info);
        }
    
        /**
         * 认证回调函数, 登录时调用
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {
            UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
            
            int activeSessionSize = getSystemService().getSessionDao().getActiveSessions(false).size();
            if (logger.isDebugEnabled()){
                logger.debug("login submit, active session size: {}, username: {}", activeSessionSize, token.getUsername());
            }
            
            // 校验登录验证码
            if (LoginController.isValidateCodeLogin(token.getUsername(), false, false)){
                Session session = UserUtils.getSession();
                String code = (String)session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);
                if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)){
                    throw new AuthenticationException("msg:验证码错误, 请重试.");
                }
            }
            
            // 校验用户名密码
            User user = getSystemService().getUserByLoginName(token.getUsername());
            if (user != null) {
                if (Global.NO.equals(user.getLoginFlag())){
                    throw new AuthenticationException("msg:该已帐号禁止登录.");
                }
                byte[] salt = Encodes.decodeHex(user.getPassword().substring(0,16));
                return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()), 
                        user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
            } else {
                return null;
            }
        }
        
        /**
         * 获取权限授权信息,如果缓存中存在,则直接从缓存中获取,否则就重新获取, 登录成功后调用
         */
        protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
            if (principals == null) {
                return null;
            }
            
            AuthorizationInfo info = null;
    
            info = (AuthorizationInfo)UserUtils.getCache(UserUtils.CACHE_AUTH_INFO);
    
            if (info == null) {
                info = doGetAuthorizationInfo(principals);
                if (info != null) {
                    UserUtils.putCache(UserUtils.CACHE_AUTH_INFO, info);
                }
            }
    
            return info;
        }
    
        /**
         * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            Principal principal = (Principal) getAvailablePrincipal(principals);
            // 获取当前已登录的用户
            if (!Global.TRUE.equals(Global.getConfig("user.multiAccountLogin"))){
                Collection<Session> sessions = getSystemService().getSessionDao().getActiveSessions(true, principal, UserUtils.getSession());
                if (sessions.size() > 0){
                    // 如果是登录进来的,则踢出已在线用户
                    if (UserUtils.getSubject().isAuthenticated()){
                        for (Session session : sessions){
                            getSystemService().getSessionDao().delete(session);
                        }
                    }
                    // 记住我进来的,并且当前用户已登录,则退出当前用户提示信息。
                    else{
                        UserUtils.getSubject().logout();
                        throw new AuthenticationException("msg:账号已在其它地方登录,请重新登录。");
                    }
                }
            }
            User user = getSystemService().getUserByLoginName(principal.getLoginName());
            if (user != null) {
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                List<Menu> list = UserUtils.getMenuList();
                for (Menu menu : list){
                    if (StringUtils.isNotBlank(menu.getPermission())){
                        // 添加基于Permission的权限信息
                        for (String permission : StringUtils.split(menu.getPermission(),",")){
                            info.addStringPermission(permission);
                        }
                    }
                }
                // 添加用户权限
                info.addStringPermission("user");
                // 添加用户角色信息
                for (Role role : user.getRoleList()){
                    info.addRole(role.getEnname());
                }
                // 更新登录IP和时间
                getSystemService().updateUserLoginInfo(user);
                // 记录登录日志
                LogUtils.saveLog(Servlets.getRequest(), "系统登录");
                return info;
            } else {
                return null;
            }
        }
        
        @Override
        protected void checkPermission(Permission permission, AuthorizationInfo info) {
            authorizationValidate(permission);
            super.checkPermission(permission, info);
        }
        
        @Override
        protected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) {
            if (permissions != null && !permissions.isEmpty()) {
                for (Permission permission : permissions) {
                    authorizationValidate(permission);
                }
            }
            return super.isPermitted(permissions, info);
        }
        
        @Override
        public boolean isPermitted(PrincipalCollection principals, Permission permission) {
            authorizationValidate(permission);
            return super.isPermitted(principals, permission);
        }
        
        @Override
        protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {
            if (permissions != null && !permissions.isEmpty()) {
                for (Permission permission : permissions) {
                    authorizationValidate(permission);
                }
            }
            return super.isPermittedAll(permissions, info);
        }
        
        /**
         * 授权验证方法
         * @param permission
         */
        private void authorizationValidate(Permission permission){
            // 模块授权预留接口
        }
        
        /**
         * 设定密码校验的Hash算法与迭代次数
         */
        @PostConstruct
        public void initCredentialsMatcher() {
            HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(SystemService.HASH_ALGORITHM);
            matcher.setHashIterations(SystemService.HASH_INTERATIONS);
            setCredentialsMatcher(matcher);
        }
        
    //  /**
    //   * 清空用户关联权限认证,待下次使用时重新加载
    //   */
    //  public void clearCachedAuthorizationInfo(Principal principal) {
    //      SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
    //      clearCachedAuthorizationInfo(principals);
    //  }
    
        /**
         * 清空所有关联认证
         * @Deprecated 不需要清空,授权缓存保存到session中
         */
        @Deprecated
        public void clearAllCachedAuthorizationInfo() {
    //      Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
    //      if (cache != null) {
    //          for (Object key : cache.keys()) {
    //              cache.remove(key);
    //          }
    //      }
        }
    
        /**
         * 获取系统业务对象
         */
        public SystemService getSystemService() {
            if (systemService == null){
                systemService = SpringContextHolder.getBean(SystemService.class);
            }
            return systemService;
        }
        
        /**
         * 授权用户信息
         */
        public static class Principal implements Serializable {
    
            private static final long serialVersionUID = 1L;
            
            private String id; // 编号
            private String loginName; // 登录名
            private String name; // 姓名
            private boolean mobileLogin; // 是否手机登录
            
    //      private Map<String, Object> cacheMap;
    
            public Principal(User user, boolean mobileLogin) {
                this.id = user.getId();
                this.loginName = user.getLoginName();
                this.name = user.getName();
                this.mobileLogin = mobileLogin;
            }
    
            public String getId() {
                return id;
            }
    
            public String getLoginName() {
                return loginName;
            }
    
            public String getName() {
                return name;
            }
    
            public boolean isMobileLogin() {
                return mobileLogin;
            }
    
    //      @JsonIgnore
    //      public Map<String, Object> getCacheMap() {
    //          if (cacheMap==null){
    //              cacheMap = new HashMap<String, Object>();
    //          }
    //          return cacheMap;
    //      }
    
            /**
             * 获取SESSIONID
             */
            public String getSessionid() {
                try{
                    return (String) UserUtils.getSession().getId();
                }catch (Exception e) {
                    return "";
                }
            }
            
            @Override
            public String toString() {
                return id;
            }
    
        }
    }
    

    6.UsernamePasswordToken

    public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken {
    
        private static final long serialVersionUID = 1L;
    
        private String captcha;
        private boolean mobileLogin;
        
        public UsernamePasswordToken() {
            super();
        }
    
        public UsernamePasswordToken(String username, char[] password,
                boolean rememberMe, String host, String captcha, boolean mobileLogin) {
            super(username, password, rememberMe, host);
            this.captcha = captcha;
            this.mobileLogin = mobileLogin;
        }
    
        public String getCaptcha() {
            return captcha;
        }
    
        public void setCaptcha(String captcha) {
            this.captcha = captcha;
        }
    
        public boolean isMobileLogin() {
            return mobileLogin;
        }
        
    }
    

    7.sessionDao

    public interface SessionDAO extends org.apache.shiro.session.mgt.eis.SessionDAO {
    
        /**
         * 获取活动会话
         * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)
         * @return
         */
        public Collection<Session> getActiveSessions(boolean includeLeave);
        
        /**
         * 获取活动会话
         * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)
         * @param principal 根据登录者对象获取活动会话
         * @param filterSession 不为空,则过滤掉(不包含)这个会话。
         * @return
         */
        public Collection<Session> getActiveSessions(boolean includeLeave, Object principal, Session filterSession);
        
    }
    

    7.自定义web会话管理类

    public class SessionManager extends DefaultWebSessionManager {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(SessionManager.class);
    
        public SessionManager() {
            super();
        }
    
        @Override
        protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
            LOGGER.info("根据token获取sessionID,确定用户是否登录");
    
            // 如果参数中包含“__sid”参数,则使用此sid会话。 例如:http://localhost/project?__sid=xxx&__cookie=true
            String sid = request.getParameter("__sid");
            if (StringUtils.isNotBlank(sid)) {
                // 是否将sid保存到cookie,浏览器模式下使用此参数。
                if (WebUtils.isTrue(request, "__cookie")) {
                    HttpServletRequest rq = (HttpServletRequest) request;
                    HttpServletResponse rs = (HttpServletResponse) response;
                    Cookie template = getSessionIdCookie();
                    Cookie cookie = new SimpleCookie(template);
                    cookie.setValue(sid);
                    cookie.saveTo(rq, rs);
                }
                // 设置当前session状态
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                        ShiroHttpServletRequest.URL_SESSION_ID_SOURCE); // session来源与url
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sid);
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
                return sid;
            } else {
                return super.getSessionId(request, response);
            }
        }
    
        @Override
        public void validateSessions() {
            super.validateSessions();
        }
    
        @Override
        protected Session retrieveSession(SessionKey sessionKey) {
            try {
                return super.retrieveSession(sessionKey);
            } catch (UnknownSessionException e) {
                // 获取不到SESSION不抛出异常
                return null;
            }
        }
    
        public Date getStartTimestamp(SessionKey key) {
            try {
                return super.getStartTimestamp(key);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
                return null;
            }
        }
    
        public Date getLastAccessTime(SessionKey key) {
            try {
                return super.getLastAccessTime(key);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
                return null;
            }
        }
    
        public long getTimeout(SessionKey key) {
            try {
                return super.getTimeout(key);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
                return 0;
            }
        }
    
        public void setTimeout(SessionKey key, long maxIdleTimeInMillis) {
            try {
                super.setTimeout(key, maxIdleTimeInMillis);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
            }
        }
    
        public void touch(SessionKey key) {
            try {
                super.touch(key);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
            }
        }
    
        public String getHost(SessionKey key) {
            try {
                return super.getHost(key);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
                return null;
            }
        }
    
        public Collection<Object> getAttributeKeys(SessionKey key) {
            try {
                return super.getAttributeKeys(key);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
                return null;
            }
        }
    
        public Object getAttribute(SessionKey sessionKey, Object attributeKey) {
            try {
                return super.getAttribute(sessionKey, attributeKey);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
                return null;
            }
        }
    
        public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) {
            try {
                super.setAttribute(sessionKey, attributeKey, value);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
            }
        }
    
        public Object removeAttribute(SessionKey sessionKey, Object attributeKey) {
            try {
                return super.removeAttribute(sessionKey, attributeKey);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
                return null;
            }
        }
    
        public void stop(SessionKey key) {
            try {
                super.stop(key);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
            }
        }
    
        public void checkValid(SessionKey key) {
            try {
                super.checkValid(key);
            } catch (InvalidSessionException e) {
                // 获取不到SESSION不抛出异常
            }
        }
    
        @Override
        protected Session doCreateSession(SessionContext context) {
            try {
                return super.doCreateSession(context);
            } catch (IllegalStateException e) {
                return null;
            }
        }
    
        @Override
        protected Session newSessionInstance(SessionContext context) {
            Session session = super.newSessionInstance(context);
            session.setTimeout(getGlobalSessionTimeout());
            return session;
        }
    
        @Override
        public Session start(SessionContext context) {
            try {
                return super.start(context);
            } catch (NullPointerException e) {
                SimpleSession session = new SimpleSession();
                session.setId(0);
                return session;
            }
        }
    }
    

    8.session缓存dao

    public class CacheSessionDAO extends EnterpriseCacheSessionDAO implements SessionDAO {
    
        private Logger logger = LoggerFactory.getLogger(getClass());
        
        public CacheSessionDAO() {
            super();
        }
    
        @Override
        protected void doUpdate(Session session) {
            if (session == null || session.getId() == null) {  
                return;
            }
            
            HttpServletRequest request = Servlets.getRequest();
            if (request != null){
                String uri = request.getServletPath();
                // 如果是静态文件,则不更新SESSION
                if (Servlets.isStaticFile(uri)){
                    return;
                }
                // 如果是视图文件,则不更新SESSION
                if (StringUtils.startsWith(uri, Global.getConfig("web.view.prefix"))
                        && StringUtils.endsWith(uri, Global.getConfig("web.view.suffix"))){
                    return;
                }
                // 手动控制不更新SESSION
                String updateSession = request.getParameter("updateSession");
                if (Global.FALSE.equals(updateSession) || Global.NO.equals(updateSession)){
                    return;
                }
            }
            super.doUpdate(session);
            logger.debug("update {} {}", session.getId(), request != null ? request.getRequestURI() : "");
        }
    
        @Override
        protected void doDelete(Session session) {
            if (session == null || session.getId() == null) {  
                return;
            }
            
            super.doDelete(session);
            logger.debug("delete {} ", session.getId());
        }
    
        @Override
        protected Serializable doCreate(Session session) {
            HttpServletRequest request = Servlets.getRequest();
            if (request != null){
                String uri = request.getServletPath();
                // 如果是静态文件,则不创建SESSION
                if (Servlets.isStaticFile(uri)){
                    return null;
                }
            }
            super.doCreate(session);
            logger.debug("doCreate {} {}", session, request != null ? request.getRequestURI() : "");
            return session.getId();
        }
    
        @Override
        protected Session doReadSession(Serializable sessionId) {
            return super.doReadSession(sessionId);
        }
        
        @Override
        public Session readSession(Serializable sessionId) throws UnknownSessionException {
            try{
                Session s = null;
                HttpServletRequest request = Servlets.getRequest();
                if (request != null){
                    String uri = request.getServletPath();
                    // 如果是静态文件,则不获取SESSION
                    if (Servlets.isStaticFile(uri)){
                        return null;
                    }
                    s = (Session)request.getAttribute("session_"+sessionId);
                }
                if (s != null){
                    return s;
                }
    
                Session session = super.readSession(sessionId);
                logger.debug("readSession {} {}", sessionId, request != null ? request.getRequestURI() : "");
                
                if (request != null && session != null){
                    request.setAttribute("session_"+sessionId, session);
                }
                
                return session;
            }catch (UnknownSessionException e) {
                return null;
            }
        }
    
        /**
         * 获取活动会话
         * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)
         * @return
         */
        @Override
        public Collection<Session> getActiveSessions(boolean includeLeave) {
            return getActiveSessions(includeLeave, null, null);
        }
        
        /**
         * 获取活动会话
         * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)
         * @param principal 根据登录者对象获取活动会话
         * @param filterSession 不为空,则过滤掉(不包含)这个会话。
         * @return
         */
        @Override
        public Collection<Session> getActiveSessions(boolean includeLeave, Object principal, Session filterSession) {
            // 如果包括离线,并无登录者条件。
            if (includeLeave && principal == null){
                return getActiveSessions();
            }
            Set<Session> sessions = Sets.newHashSet();
            for (Session session : getActiveSessions()){
                boolean isActiveSession = false;
                // 不包括离线并符合最后访问时间小于等于3分钟条件。
                if (includeLeave || DateUtils.pastMinutes(session.getLastAccessTime()) <= 3){
                    isActiveSession = true;
                }
                // 符合登陆者条件。
                if (principal != null){
                    PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
                    if (principal.toString().equals(pc != null ? pc.getPrimaryPrincipal().toString() : StringUtils.EMPTY)){
                        isActiveSession = true;
                    }
                }
                // 过滤掉的SESSION
                if (filterSession != null && filterSession.getId().equals(session.getId())){
                    isActiveSession = false;
                }
                if (isActiveSession){
                    sessions.add(session);
                }
            }
            return sessions;
        }
        
    }
    

    相关文章

      网友评论

      本文标题:Shiro实现后台和前端共用

      本文链接:https://www.haomeiwen.com/subject/xwkqhxtx.html