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

com.lx.boot.web.AuthUtil Maven / Gradle / Ivy

package com.lx.boot.web;

import com.lx.annotation.Note;
import com.lx.boot.OS;
import com.lx.entity.JwtInfo;
import com.lx.entity.UserInfo;
import com.lx.util.LX;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

import static com.lx.constant.DefaultBaseConstant.*;
import static com.lx.constant.DefaultRedisConstant.RedisPrefix.*;


@Slf4j
@Component
@Note("登录信息工具类")
public class AuthUtil {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //说明: 生成token
    /**{ ylx } 2022/4/1 13:43 */
    @Note("登录时创建token, 参数可为UserInfo的子类")
    public String createToken(@Valid @NotNull(message = "用户信息不能为空!")UserInfo userInfo){
        String token = LX.uuid32();
        int time = OS.getIntProperty(SERVER_TOKEN_TIMEOUT_MINUTES+"."+userInfo.getTokenType(),"0");
        if (time <=0){
            time = OS.getIntProperty(SERVER_TOKEN_TIMEOUT_MINUTES,"600");
        }
        // 保存用户信息
        stringRedisTemplate.opsForValue().set(USER_LOGIN_INFO_USER_INFO_APPID_BY_TOKEN+token,LX.toJSONString(userInfo),time, TimeUnit.MINUTES);
        // 删除上次token 默认单个地方登录
        if (!OS.getPropertyIsTrue(SERVER_AT_SAME_TIME_LOGIN,"false")){
            deleteToken(userInfo);
        }
        // 保存用户id和用户类型对应的token
        stringRedisTemplate.opsForValue().set(USER_LOGIN_INFO_TOKEN_BY_USER_ID_USER_TYPE+userInfo.getUserId()+userInfo.getTokenType(),token,time, TimeUnit.MINUTES);
        return token;
    }

    //说明: 删除用户登录的token
    /**{ ylx } 2022/4/1 14:04 */
    @Note("删除用户登录的token")
    public void deleteToken(@Valid @NotNull(message = "用户信息不能为空!") UserInfo userInfo){
        String token = (String) stringRedisTemplate.opsForValue().get(USER_LOGIN_INFO_TOKEN_BY_USER_ID_USER_TYPE + userInfo.getUserId() + userInfo.getTokenType());
        stringRedisTemplate.delete(USER_LOGIN_INFO_USER_INFO_APPID_BY_TOKEN+token);
    }


    //说明: 获取用户信息
    /**{ ylx } 2022/4/1 11:38 */
    @Note("获取用户信息")
    public UserInfo getUserInfo(HttpServletRequest request){
        return getUserInfo(UserInfo.class, request);
    }
    //说明: 获取用户信息
    /**{ ylx } 2022/4/1 11:38 */
    @Note("获取用户信息, T为UserInfo的子类")
    public T getUserInfo(Class t, HttpServletRequest request){
        try {
            String token = request.getHeader(AUTHORIZATION);
            if (LX.isEmpty(token)){
                return null;
            }
            if (token.startsWith(JWT_HEADER)){
                //jwt Token
                return (T) getJwtUserInfo(token);
            }
            return LX.toObj(t, stringRedisTemplate.opsForValue().get(USER_LOGIN_INFO_USER_INFO_APPID_BY_TOKEN + token));
        }catch (Exception e){
            log.error("获取用户信息时发生错误!", e);
            return null;
        }
    }

    @Note("登录时创建JWT token, 参数可为UserInfo的子类  注意:该类型未控制用户在多个位置同时登录")
    public String createJwtToken(@Valid @NotNull(message = "用户信息不能为空!")UserInfo userInfo){
        int time = OS.getIntProperty(SERVER_TOKEN_TIMEOUT_MINUTES+"."+userInfo.getTokenType(),"0");
        if (time <=0){
            time = OS.getIntProperty(SERVER_TOKEN_TIMEOUT_MINUTES,"600");
        }
        return createJwtToken(userInfo, TimeUnit.MINUTES, time);
    }

    public static void main(String[]args){
        System.out.println((char) (byte)46);
    }

    private final static String JWT_HEADER = base64UrlEncode("{\"alg\": \"HS256\",\"typ\": \"JWT\"}");
    @Note("创建jwt")
    private static String createJwtToken(UserInfo userInfo,TimeUnit timeUnit, long time){
        JwtInfo jwtInfo = new JwtInfo(userInfo,timeUnit,time);
        String payloadJson = LX.toJSONString(jwtInfo);
        String payload = base64UrlEncode(payloadJson);
        String key = OS.getProperty(SERVER_JWT_KEY,DEFAULT_SERVER_JWT_KEY);
        byte[] res = LX.HmacSha.HmacSHA256.encode(key.getBytes(StandardCharsets.UTF_8),JWT_HEADER.getBytes(StandardCharsets.UTF_8),new byte[]{(byte)46},payload.getBytes(StandardCharsets.UTF_8));
        return JWT_HEADER+"."+payload+"."+base64UrlEncode(res);
    }

    @Note("通过jwt获取用户信息")
    private static UserInfo getJwtUserInfo(String token){
        if (LX.isEmpty(token)){
            return null;
        }
        String[] split = token.split("\\.");
        if (split.length != 3){
            return null;
        }
        String header = split[0];
        String payload = split[1];
        String key = OS.getProperty(SERVER_JWT_KEY,DEFAULT_SERVER_JWT_KEY);
        byte[] res = LX.HmacSha.HmacSHA256.encode(key.getBytes(StandardCharsets.UTF_8),header.getBytes(StandardCharsets.UTF_8),new byte[]{(byte)46},payload.getBytes(StandardCharsets.UTF_8));
        if (split[2].equals(base64UrlEncode(res))){
            JwtInfo jwtInfo = LX.toObj(JwtInfo.class, LX.decode(split[1]));
            if (!jwtInfo.expired()){
                return jwtInfo.getUserInfo();
            }
        }
        return null;
    }
    @Note("使用无填充的 base64URL 进行编码")
    private static String base64UrlEncode(byte[] data){
        return Base64.getUrlEncoder().withoutPadding().encodeToString(data);
    }
    private static String base64UrlEncode(String data){
        return Base64.getUrlEncoder().withoutPadding().encodeToString(data.getBytes(StandardCharsets.UTF_8));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy