用户冻结功能实现

535 阅读1分钟

今天做了一个冻结/解冻用户的功能,这里记录下思路

1. 冻结

1.修改数据库用户状态信息
2.将用户拉黑状态存入缓存

// 拉黑token
String userKey = CacheName.TOKEN_UNICODE_FROZEN_ORDER + ":" + changeAccountCode;
// 1.2 加入 黑名单
CacheForHash.set(userKey, changeAccountCode, true);

2. 解冻

  1. 修改数据库用户状态
  2. 删除用户拉黑缓存
//账户进行解冻操作
int i = accountDao.accountUnfreeze(params);
// 删除拉黑token
String userKey = CacheName.TOKEN_UNICODE_FROZEN_ORDER + ":" + changeAccountCode;
// 1.2 删除 黑名单
CacheForHash.delete(userKey);

3. 拦截

在解析token时,获取缓存信息,查看是否存在拉黑账号

import com.hdx.common.CacheName;
import com.jate.base.cache.CacheForHash;
import com.jate.base.exception.BaseException;
import com.jate.base.util.HttpUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author jate
 * @version 1.0.0
 * @Description 资源token解析加载
 * @Date 2019/4/4
 */
@Component
@Data
@Slf4j
public class BaseResourceServerTokenServices implements ResourceServerTokenServices {
    private TokenStore tokenStore;
    private DefaultAccessTokenConverter defaultAccessTokenConverter;
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    @Resource
    private UserAuthenticationConverter userTokenConverter;
    @Resource
    private IRefreshToken refreshToken;
    @Resource
    private Redisson redisson;

    /**
     * 加载token信息 并判断是否过期
     *
     * @param accessToken
     * @return
     * @throws AuthenticationException
     * @throws InvalidTokenException
     */
    @Override
    public OAuth2Authentication loadAuthentication(String accessToken)
            throws AuthenticationException, InvalidTokenException {
        OAuth2Authentication oAuth2Authentication = tokenStore.readAuthentication(accessToken);
        defaultAccessTokenConverter.setUserTokenConverter(userTokenConverter);
        Map<String, ?> map = jwtAccessTokenConverter.convertAccessToken(readAccessToken(accessToken),
                oAuth2Authentication);
        long exp = (Long) map.get("exp") * 1000;
        long nowDate = System.currentTimeMillis();
        String accountCode = (String) map.get("accountCode");
        String jti = (String) map.get("jti");
        //获取用户是否记住密码
        Object remember = map.get("isRemember");
        Boolean isRemember = false;
        if (remember != null) {
            isRemember = Boolean.valueOf(remember.toString());
        }
        if (exp < nowDate && !isRemember) {
            throw new InvalidTokenException("请登录!");
        }
        if (!map.containsKey("aud")) {
            if (CacheForHash.hasKey(CacheName.TOKEN_UNICODE_BLACK_ORDER, jti)) {
                throw new InvalidTokenException(TokenCommon.OFFLINE);
            } else if (CacheForHash.hasKey(CacheName.TOKEN_UNICODE_FROZEN_ORDER + ":" + accountCode, accountCode)) {
                throw new InvalidTokenException(TokenCommon.FROZEN);
            }
            //记住密码刷新token
            if (isRemember) {
                exp = (exp - nowDate) / 1000 / 60;
                if (exp <= 2) {// 执行刷新token
                    RLock lock = redisson.getLock("sys:token:" + accountCode);
                    lock.lock(1000, TimeUnit.MILLISECONDS);
                    try {
                        String lastKey = CacheName.USER + accountCode + ":" + jti;
                        if (CacheForHash.hasKey(lastKey, CacheName.TOKEN)) {
                            HttpUtil.getResponse().setHeader("access_token",
                                    CacheForHash.get(lastKey, CacheName.TOKEN, String.class));
                            throw new InvalidTokenException(TokenCommon.REFRESH_TOKEN);
                        }
                        int refreshStatus = refreshToken.refreshToken(map);
                        if (refreshStatus == 1)
                            throw new BaseException(100, "请登录!");
                        else if (refreshStatus == 3) {
                            throw new InvalidTokenException(TokenCommon.REFRESH_TOKEN);
                        }
                    } catch (InvalidTokenException e) {
                        throw new InvalidTokenException(TokenCommon.REFRESH_TOKEN);
                    } catch (BaseException e) {
                        throw new InvalidTokenException("请登录!");
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }
        try {
            HttpServletRequest request = HttpUtil.getRequest();
            request.setAttribute("jti", jti);//登录后的唯一签名标识
            request.setAttribute("accountCode", map.get("accountCode"));//用户唯一标识
            request.setAttribute("subAccountCode", map.get("subAccount"));//用户唯一标识
        } catch (Exception e) {
        }
        return defaultAccessTokenConverter.extractAuthentication(map);
    }

    /**
     * 读取token
     *
     * @param accessToken
     * @return
     */
    @Override
    public OAuth2AccessToken readAccessToken(String accessToken) {
        return tokenStore.readAccessToken(accessToken);
    }
}