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

shz.spring.token.AbstractTokenService Maven / Gradle / Ivy

There is a newer version: 2023.2.5
Show newest version
package shz.spring.token;

import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import eu.bitwalker.useragentutils.Version;
import shz.core.Coder;
import shz.core.hash.MdHash;
import shz.core.msg.ServerFailureMsg;
import shz.core.security.encryption.DefaultSymmetricalEncipher;
import shz.spring.ServletHelp;
import shz.spring.auth.AuthService;
import shz.spring.session.Session;
import shz.spring.session.SessionHolder;

import javax.servlet.http.HttpServletRequest;
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.Objects;
import java.util.Optional;

public abstract class AbstractTokenService implements TokenService {
    final int expireSecond;
    final int delaySecond;
    final String key;
    final AuthService authService;

    protected AbstractTokenService(int expireSecond, int delaySecond, String key, AuthService authService) {
        ServerFailureMsg.requireNon(expireSecond <= 0, "生成token有效时间必须大于0");
        ServerFailureMsg.requireNon(delaySecond < 0, "生成token延迟时间不能小于0");
        this.expireSecond = expireSecond;
        this.delaySecond = delaySecond;
        this.key = key;
        this.authService = authService;
    }

    @Override
    public final String generate(Session session) {
        ServerFailureMsg.requireNonNull(session.getUserid(), "生成token用户id不能为空");
        ServerFailureMsg.requireNonNull(session.getRoleId(), "生成token角色id不能为空");
        DefaultSymmetricalEncipher.Detail detail = encipherDetail(session.getUserid());
        ServerFailureMsg.requireNonNull(detail, "用户id:%d缺少加密信息", session.getUserid());

        long nowMillis = System.currentTimeMillis();
        long startTimestamp = nowMillis + delaySecond * 1000L;
        long endTimestamp = startTimestamp + expireSecond * 1000L;

        byte[] identity = identity(session);
        ByteBuffer buffer = ByteBuffer.allocate(16 + identity.length);
        buffer.putLong(startTimestamp);
        buffer.putLong(endTimestamp);
        buffer.put(identity);

        byte[] ciphertext = new DefaultSymmetricalEncipher(detail).encrypt(buffer.array());
        buffer = ByteBuffer.allocate(16 + ciphertext.length);
        buffer.putLong(session.getUserid());
        buffer.putLong(session.getRoleId());
        buffer.put(ciphertext);

        String token = Base64.getEncoder().encodeToString(buffer.array());
        saveIdentity(session.getUserid(), Coder.hexEncode(identity), (expireSecond + delaySecond) * 1000L);
        return token;
    }

    protected abstract DefaultSymmetricalEncipher.Detail encipherDetail(long userid);

    private byte[] identity(Session session) {
        return MdHash.SHA256.hash(signData(session).getBytes());
    }

    @Override
    public final String getToken(HttpServletRequest request) {
        String token = ServletHelp.getKey(request, key);
        if (token == null) return null;
        if (token.startsWith("Bearer ")) return token.substring(7);
        return token;
    }

    @Override
    public final TokenIdentity getTokenIdentity(String token) {
        if (token == null) return null;
        TokenIdentity tokenIdentity = null;
        try {
            ByteBuffer buffer = ByteBuffer.wrap(Base64.getDecoder().decode(token.getBytes()));
            tokenIdentity = new TokenIdentity(buffer.getLong(), buffer.getLong());
            tokenIdentity.identity = new byte[buffer.remaining()];
            buffer.get(tokenIdentity.identity);
        } catch (Exception ignored) {
        }
        return tokenIdentity;
    }

    @Override
    public final TokenIdentity getTokenIdentity(HttpServletRequest request) {
        return getTokenIdentity(getToken(request));
    }

    @Override
    public final TokenInfo getTokenInfo(TokenIdentity tokenIdentity) {
        if (tokenIdentity == null) return null;
        TokenInfo info = new TokenInfo();
        info.setUserid(tokenIdentity.userid);
        info.setRoleId(tokenIdentity.roleId);
        try {
            DefaultSymmetricalEncipher.Detail detail = encipherDetail(info.getUserid());
            if (detail != null) {
                ByteBuffer buffer = ByteBuffer.wrap(new DefaultSymmetricalEncipher(detail).decrypt(tokenIdentity.identity));
                info.setStartTimestamp(buffer.getLong());
                info.setEndTimestamp(buffer.getLong());
                byte[] identity = new byte[buffer.remaining()];
                buffer.get(identity);
                info.setIdentity(Coder.hexEncode(identity));
            }
        } catch (Exception ignored) {
        }
        return info;
    }

    @Override
    public final TokenInfo getTokenInfo(HttpServletRequest request) {
        return getTokenInfo(getTokenIdentity(request));
    }

    @Override
    public final boolean verify(TokenInfo tokenInfo, Session session) {
        if (tokenInfo == null || tokenInfo.getIdentity() == null) return false;
        long nowMillis = System.currentTimeMillis();
        if (tokenInfo.getStartTimestamp() > nowMillis || tokenInfo.getEndTimestamp() < nowMillis) return false;
        return Objects.equals(Coder.hexEncode(identity(session)), tokenInfo.getIdentity());
    }

    @Override
    public final boolean isLogin(TokenInfo tokenInfo) {
        return Objects.equals(getIdentity(tokenInfo.getUserid()), tokenInfo.getIdentity());
    }

    @Override
    public final boolean isLogin(Session session) {
        return session.getUserid() != null && Objects.equals(getIdentity(session.getUserid()), Coder.hexEncode(identity(session)));
    }

    @Override
    public final void logout(Long userid) {
        if (userid != null) {
            Session session = SessionHolder.get();
            if (session != null) {
                authService.checkUserPermission(session.getUserid(), session.getRoleId(), userid);
                deleteIdentity(userid);
            }
        }
    }

    @Override
    public final void logout() {
        Session session = SessionHolder.get();
        if (session != null) {
            Long userid = session.getUserid();
            if (userid != null) deleteIdentity(userid);
        }
    }

    @Override
    public final boolean refresh(Long userid) {
        if (userid == null) return false;
        Session session = SessionHolder.get();
        if (session == null) return false;
        authService.checkUserPermission(session.getUserid(), session.getRoleId(), userid);
        return expireIdentity(userid, expireSecond * 1000L);
    }

    @Override
    public final boolean refresh() {
        Session session = SessionHolder.get();
        return session != null && session.getUserid() != null && expireIdentity(session.getUserid(), expireSecond * 1000L);
    }

    @Override
    public String signData(Session session) {
        return session.getIp() + "-" +
                session.getMac() + "-" +
                session.getBrowser() + "-" +
                session.getBrowserVersion() + "-" +
                session.getOs();
    }

    @Override
    public String signData(HttpServletRequest request) {
        UserAgent userAgent = ServletHelp.getUserAgent(request);
        return ServletHelp.getIp(request) + "-" +
                request.getHeader("Mac") + "-" +
                Optional.ofNullable(userAgent.getBrowser()).map(Browser::getName).orElse(null) + "-" +
                Optional.ofNullable(userAgent.getBrowserVersion()).map(Version::getVersion).orElse(null) + "-" +
                Optional.ofNullable(userAgent.getOperatingSystem()).map(OperatingSystem::getName).orElse(null);
    }

    protected abstract void saveIdentity(long userid, String identity, long expireMillis);

    protected abstract String getIdentity(long userid);

    protected abstract void deleteIdentity(long userid);

    protected abstract boolean expireIdentity(long userid, long expireMillis);
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy