All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.ocoop.framework.safe.SessionManager Maven / Gradle / Ivy

package cn.ocoop.framework.safe;

import cn.ocoop.framework.safe.auth.service.AuthorizingService;
import cn.ocoop.framework.safe.utils.CookieUtils;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.servlet.http.HttpServletResponse;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

@Slf4j
@Data
public class SessionManager {

    private static final String SESSION_PMS_REFRESH_ATTR_KEY = "_LAST_PMS_REFRESH_TIME";
    private static final String DEFAULT_STATE_ATTR_KEY = "_STATE";
    private static final String INVALID_STATE_ATTR_VALUE = "_INVALID";
    public static SafeProperties safeProperties;
    public static CaptchaProperties captchaProperties;
    public static StringRedisTemplate redisTemplate;
    public static AuthorizingService authorizingService;

    public static BoundHashOperations getSession(String sessionId) {
        return redisTemplate.boundHashOps(getSessionkey(sessionId));
    }

    public static BoundHashOperations getSession() {

        if (WebContext.get().getSessionId() == null) {
            String sessionId = createSessionId();
            SessionManager.createSession(WebContext.get().getResponse(), sessionId);
            WebContext.get().setSessionId(sessionId);
            log.info("new session[{}] is created!", sessionId);
        }

        return redisTemplate.boundHashOps(getSessionkey(WebContext.get().getSessionId()));
    }

    public static List> getSession(long accountId) {
        Set keys = redisTemplate.keys(getSessionMapKey(accountId, "*"));

        List> sessions = Lists.newArrayList();

        if (CollectionUtils.isNotEmpty(keys)) {
            for (String key : keys) {
                sessions.add(getSession(redisTemplate.opsForValue().get(key)));
            }
        }

        return sessions;
    }

    public static void setAttribute(long accountId, String key, String value) {
        for (BoundHashOperations session : getSession(accountId)) {
            session.put(key, value);
        }
    }

    public static void removeAttribute(long accountId, String key) {
        for (BoundHashOperations session : getSession(accountId)) {
            session.delete(key);
        }
    }

    public static String createSessionId() {
        return UUID.randomUUID().toString();
    }

    public static void setAttribute(String key, String value) {
        getSession().put(key, value);
    }

    public static String getAttribute(String key) {
        return getSession().get(key);
    }

    public static void removeAttribute(String key) {
        getSession().delete(key);
    }

    public static void logout(HttpServletResponse response) {
        getCurrentAccountId().ifPresent(accountId -> {
            redisTemplate.delete(Lists.newArrayList(
                    WebContext.get().getSessionId(),
                    getSessionMapKey(accountId, WebContext.get().getSessionId()),
                    getRoleKey(accountId),
                    getPmsKey(accountId)
            ));

            CookieUtils.clear(response, safeProperties.getSessionIdCookieName());
        });
    }

    private static BoundHashOperations createSession(HttpServletResponse response, String sessionId, Long accountId) {
        BoundHashOperations hash = redisTemplate.boundHashOps(getSessionkey(sessionId));

        hash.put(SafeProperties.DEFAULT_SESSION_ID, sessionId);
        hash.expire(2, TimeUnit.DAYS);
        if (accountId != null) {
            hash.put("accountId", String.valueOf(accountId));
            redisTemplate.opsForValue().set(getSessionMapKey(accountId, sessionId), sessionId, 2, TimeUnit.DAYS);
        }

        CookieUtils.store(response, safeProperties.getSessionIdCookieName(), sessionId);
        return hash;
    }

    public static BoundHashOperations createSession(HttpServletResponse response, String sessionId) {
        return createSession(response, sessionId, null);
    }

    /**
     * 创建已认证的会话
     *
     * @param response
     * @param accountId
     * @return
     */
    public static BoundHashOperations createAuthenticatedSession(HttpServletResponse response, Long accountId) {
        BoundHashOperations lastSession = getSession();

        BoundHashOperations session = createSession(response, createSessionId(), accountId);
        Map entries = lastSession.entries();
        if (entries != null) {
            for (String key : entries.keySet()) {
                if ("accountId".equals(key) || SafeProperties.DEFAULT_SESSION_ID.equals(key) || entries.get(key) == null) {
                    continue;
                }

                session.put(key, entries.get(key));
            }
        }

        clearLastSession(accountId, WebContext.get().getSessionId());
        return session;
    }

    private static void clearLastSession(Long accountId, String sessionId) {
        redisTemplate.delete(getSessionkey(sessionId));
        if (accountId != null) {
            redisTemplate.delete(getSessionMapKey(accountId, sessionId));
        }
    }

    private static String getSessionkey(String sessionId) {
        return safeProperties.getSessionKeyPrefix() + sessionId;
    }

    private static String getSessionMapKey(long accountId, String sessionId) {
        return safeProperties.getSessionMapKeyPrefix() + accountId + ":" + sessionId;
    }

    public static boolean isLogin(String sessionId) {
        BoundHashOperations session = getSession(sessionId);
        return StringUtils.isNotBlank(session.get("accountId"));
    }

    public static boolean isLogin() {
        BoundHashOperations session = getSession();
        return StringUtils.isNotBlank(session.get("accountId"));
    }

    public static boolean touch(String sessionId) {
        Boolean expire = redisTemplate.expire(getSessionkey(sessionId), 2, TimeUnit.DAYS);
        if (BooleanUtils.isNotTrue(expire)) return false;

        if (isLogin(sessionId)) {
            redisTemplate.opsForValue().set(getSessionMapKey(NumberUtils.toLong(getSession(sessionId).get("accountId")), sessionId), sessionId, 2, TimeUnit.DAYS);
        }

        return true;
    }

    private static String getPmsKey(long accountId) {
        return "permissions:account_id:" + accountId;
    }

    private static String getRoleKey(long accountId) {
        return "roles:account_id:" + accountId;
    }

    public static Optional getCurrentAccountId() {
        BoundHashOperations session = getSession(WebContext.get().getSessionId());
        if (StringUtils.isBlank(session.get("accountId"))) return Optional.empty();

        return Optional.of(NumberUtils.toLong(session.get("accountId")));
    }

    public static void clearAllRoleAndPermission() {
        redisTemplate.delete(safeProperties.getPermissionKey());
    }

    public static void clearRoleAndPermission(long accountId) {
        clearRole(accountId);
        clearPermission(accountId);
    }

    public static void clearRoleAndPermission() {
        getCurrentAccountId().ifPresent(accountId -> {
            clearRole(accountId);
            clearPermission(accountId);
        });
    }

    public static void clearRole(long accountId) {
        redisTemplate.opsForHash().delete(
                safeProperties.getPermissionKey(),
                getRoleKey(accountId)
        );
    }

    public static void clearPermission(long accountId) {
        redisTemplate.opsForHash().delete(
                safeProperties.getPermissionKey(),
                getPmsKey(accountId)
        );
    }

    public static void refreshCachedRoleAndPermissionIfNecessary() {
        String cachedRefreshTime = getAttribute(SESSION_PMS_REFRESH_ATTR_KEY);
        if (cachedRefreshTime == null) return;

        String refreshTime = redisTemplate.opsForValue().get(safeProperties.getPermissionRefreshKey());
        if (refreshTime == null || Long.parseLong(cachedRefreshTime) > Long.parseLong(refreshTime)) return;

        clearRoleAndPermission();
    }

    @SuppressWarnings("unchecked")
    public static List getPermission() {
        Optional AccountIdOptional = getCurrentAccountId();
        if (!AccountIdOptional.isPresent()) {
            return Lists.newArrayList();
        }

        BoundHashOperations pmsStore = redisTemplate.boundHashOps(safeProperties.getPermissionKey());

        String pmsKey = getPmsKey(AccountIdOptional.get());
        if (BooleanUtils.isNotTrue(pmsStore.hasKey(pmsKey))) {
            List pms = authorizingService.listPermission(AccountIdOptional.get());
            if (CollectionUtils.isEmpty(pms)) {
                pms = Lists.newArrayList();
            }
            pmsStore.put(pmsKey, JSON.toJSONString(pms));
        }

        return JSON.parseObject(pmsStore.get(pmsKey), List.class);
    }

    @SuppressWarnings("unchecked")
    public static List getRole() {
        Optional AccountIdOptional = getCurrentAccountId();
        if (!AccountIdOptional.isPresent()) {
            return Lists.newArrayList();
        }

        BoundHashOperations roleStore = redisTemplate.boundHashOps(safeProperties.getPermissionKey());

        String roleKey = getRoleKey(AccountIdOptional.get());
        if (BooleanUtils.isNotTrue(roleStore.hasKey(roleKey))) {
            List pms = authorizingService.listRole(AccountIdOptional.get());
            if (CollectionUtils.isEmpty(pms)) {
                pms = Lists.newArrayList();
            }
            roleStore.put(roleKey, JSON.toJSONString(pms));
            roleStore.put(SESSION_PMS_REFRESH_ATTR_KEY, String.valueOf(Instant.now().toEpochMilli()));
        }

        return JSON.parseObject(roleStore.get(roleKey), List.class);
    }

    public static boolean hasRole(String... role) {
        return getRole().containsAll(Arrays.asList(role));
    }

    public static boolean hasAnyRole(String... role) {
        List role1 = getRole();
        return Stream.of(role).anyMatch(role1::contains);
    }

    public static boolean hasPermission(String... pms) {
        return getPermission().containsAll(Arrays.asList(pms));
    }

    public static boolean hasAnyPermission(String... pms) {
        List pms1 = getPermission();
        return Stream.of(pms).anyMatch(pms1::contains);
    }


    public static void refreshAllRoleAndPermission(String... key) {
        if (ArrayUtils.isEmpty(key)) {
            redisTemplate.opsForValue().set(safeProperties.getPermissionRefreshKey(), String.valueOf(Instant.now().toEpochMilli()));
            return;
        }

        Stream.of(key).forEach(k -> redisTemplate.opsForValue().set(k, String.valueOf(Instant.now().toEpochMilli())));
    }

    public static void invalid(long accountId) {
        setAttribute(accountId, DEFAULT_STATE_ATTR_KEY, INVALID_STATE_ATTR_VALUE);
    }

    public static void valid(long accountId) {
        removeAttribute(accountId, DEFAULT_STATE_ATTR_KEY);
    }

    public static boolean isValidSessionState() {
        return !INVALID_STATE_ATTR_VALUE.equals(getAttribute(DEFAULT_STATE_ATTR_KEY));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy