mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-10 19:51:00 +00:00
(feat)Support for managing large models with Dify #1830;2、add user access token; #1829; 3、support change password #1824 (#1839)
This commit is contained in:
@@ -3,6 +3,7 @@ package com.tencent.supersonic.auth.api.authentication.adaptor;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
||||
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
||||
import com.tencent.supersonic.common.pojo.User;
|
||||
|
||||
@@ -27,4 +28,16 @@ public interface UserAdaptor {
|
||||
List<User> getUserByOrg(String key);
|
||||
|
||||
Set<String> getUserAllOrgId(String userName);
|
||||
|
||||
String getPassword(String userName);
|
||||
|
||||
void resetPassword(String userName, String password, String newPassword);
|
||||
|
||||
UserToken generateToken(String name, String userName, long expireTime);
|
||||
|
||||
void deleteUserToken(Long id);
|
||||
|
||||
UserToken getUserToken(Long id);
|
||||
|
||||
List<UserToken> getUserTokens(String userName);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.tencent.supersonic.auth.api.authentication.pojo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserToken {
|
||||
private Integer id;
|
||||
private String name;
|
||||
private String userName;
|
||||
private String token;
|
||||
private Long expireTime;
|
||||
private Date createDate;
|
||||
private Date expireDate;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.tencent.supersonic.auth.api.authentication.request;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserTokenReq {
|
||||
@NotBlank(message = "name can not be null")
|
||||
private String name;
|
||||
|
||||
@NotBlank(message = "expireTime can not be null")
|
||||
private long expireTime;
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
||||
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
||||
import com.tencent.supersonic.common.pojo.User;
|
||||
|
||||
@@ -30,4 +31,16 @@ public interface UserService {
|
||||
List<User> getUserByOrg(String key);
|
||||
|
||||
List<Organization> getOrganizationTree();
|
||||
|
||||
String getPassword(String userName);
|
||||
|
||||
void resetPassword(String userName, String password, String newPassword);
|
||||
|
||||
UserToken generateToken(String name, String userName, long expireTime);
|
||||
|
||||
List<UserToken> getUserTokens(String userName);
|
||||
|
||||
UserToken getUserToken(Long id);
|
||||
|
||||
void deleteUserToken(Long id);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package com.tencent.supersonic.auth.authentication.adaptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.tencent.supersonic.auth.api.authentication.adaptor.UserAdaptor;
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
|
||||
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserTokenDO;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.repository.UserRepository;
|
||||
import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
||||
import com.tencent.supersonic.common.pojo.User;
|
||||
@@ -15,8 +19,8 @@ import com.tencent.supersonic.common.util.ContextUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -106,6 +110,68 @@ public class DefaultUserAdaptor implements UserAdaptor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword(String userName) {
|
||||
UserDO userDO = getUser(userName);
|
||||
if (userDO == null) {
|
||||
throw new RuntimeException("user not exist,please register");
|
||||
}
|
||||
return userDO.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPassword(String userName, String password, String newPassword) {
|
||||
UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
|
||||
Optional<UserDO> userDOOptional = Optional.ofNullable(getUser(userName));
|
||||
|
||||
UserDO userDO = userDOOptional
|
||||
.orElseThrow(() -> new RuntimeException("User does not exist, please register"));
|
||||
|
||||
try {
|
||||
validateOldPassword(userDO, password);
|
||||
updatePassword(userDO, newPassword, userRepository);
|
||||
} catch (PasswordEncryptionException e) {
|
||||
throw new RuntimeException("Password encryption error, please try again", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void validateOldPassword(UserDO userDO, String password)
|
||||
throws PasswordEncryptionException {
|
||||
String oldPassword = encryptPassword(password, userDO.getSalt());
|
||||
if (!userDO.getPassword().equals(oldPassword)) {
|
||||
throw new RuntimeException("Old password is not correct, please try again");
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePassword(UserDO userDO, String newPassword, UserRepository userRepository)
|
||||
throws PasswordEncryptionException {
|
||||
try {
|
||||
byte[] salt = AESEncryptionUtil.generateSalt(userDO.getName());
|
||||
userDO.setSalt(AESEncryptionUtil.getStringFromBytes(salt));
|
||||
userDO.setPassword(AESEncryptionUtil.encrypt(newPassword, salt));
|
||||
userRepository.updateUser(userDO);
|
||||
} catch (Exception e) {
|
||||
throw new PasswordEncryptionException("Error encrypting password", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String encryptPassword(String password, String salt)
|
||||
throws PasswordEncryptionException {
|
||||
try {
|
||||
return AESEncryptionUtil.encrypt(password, AESEncryptionUtil.getBytesFromString(salt));
|
||||
} catch (Exception e) {
|
||||
throw new PasswordEncryptionException("Error encrypting password", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PasswordEncryptionException extends Exception {
|
||||
public PasswordEncryptionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
private UserWithPassword getUserWithPassword(UserReq userReq) {
|
||||
UserDO userDO = getUser(userReq.getName());
|
||||
if (userDO == null) {
|
||||
@@ -136,4 +202,70 @@ public class DefaultUserAdaptor implements UserAdaptor {
|
||||
public Set<String> getUserAllOrgId(String userName) {
|
||||
return Sets.newHashSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserToken generateToken(String name, String userName, long expireTime) {
|
||||
TokenService tokenService = ContextUtils.getBean(TokenService.class);
|
||||
UserDO userDO = getUser(userName);
|
||||
if (userDO == null) {
|
||||
throw new RuntimeException("user not exist,please register");
|
||||
}
|
||||
UserWithPassword userWithPassword =
|
||||
new UserWithPassword(userDO.getId(), userDO.getName(), userDO.getDisplayName(),
|
||||
userDO.getEmail(), userDO.getPassword(), userDO.getIsAdmin());
|
||||
|
||||
String token =
|
||||
tokenService.generateToken(UserWithPassword.convert(userWithPassword), expireTime);
|
||||
UserTokenDO userTokenDO = saveUserToken(name, userName, token, expireTime);
|
||||
return convertUserToken(userTokenDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUserToken(Long id) {
|
||||
UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
|
||||
userRepository.deleteUserToken(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserToken getUserToken(Long id) {
|
||||
UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
|
||||
return convertUserToken(userRepository.getUserToken(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserToken> getUserTokens(String userName) {
|
||||
UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
|
||||
List<UserToken> userTokens = userRepository.getUserTokenListByName(userName).stream()
|
||||
.map(this::convertUserToken).collect(Collectors.toList());
|
||||
return userTokens;
|
||||
}
|
||||
|
||||
private UserTokenDO saveUserToken(String tokenName, String userName, String token,
|
||||
long expireTime) {
|
||||
UserTokenDO userTokenDO = new UserTokenDO();
|
||||
userTokenDO.setName(tokenName);
|
||||
userTokenDO.setUserName(userName);
|
||||
userTokenDO.setToken(token);
|
||||
userTokenDO.setExpireTime(expireTime);
|
||||
userTokenDO.setCreateTime(new java.util.Date());
|
||||
userTokenDO.setCreateBy(userName);
|
||||
userTokenDO.setUpdateBy(userName);
|
||||
userTokenDO.setExpireDateTime(new java.util.Date(System.currentTimeMillis() + expireTime));
|
||||
UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
|
||||
userRepository.addUserToken(userTokenDO);
|
||||
|
||||
return userTokenDO;
|
||||
}
|
||||
|
||||
private UserToken convertUserToken(UserTokenDO userTokenDO) {
|
||||
UserToken userToken = new UserToken();
|
||||
userToken.setId(userTokenDO.getId());
|
||||
userToken.setName(userTokenDO.getName());
|
||||
userToken.setUserName(userTokenDO.getUserName());
|
||||
userToken.setToken(userTokenDO.getToken());
|
||||
userToken.setExpireTime(userTokenDO.getExpireTime());
|
||||
userToken.setCreateDate(userTokenDO.getCreateTime());
|
||||
userToken.setExpireDate(userTokenDO.getExpireDateTime());
|
||||
return userToken;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.tencent.supersonic.auth.authentication.interceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
||||
import com.tencent.supersonic.auth.api.authentication.constant.UserConstants;
|
||||
import com.tencent.supersonic.auth.authentication.service.UserServiceImpl;
|
||||
@@ -13,7 +15,6 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.tencent.supersonic.auth.authentication.interceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.annotation.AuthenticationIgnore;
|
||||
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
|
||||
@@ -14,8 +17,6 @@ import io.jsonwebtoken.Claims;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.tencent.supersonic.auth.authentication.persistence.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@TableName("s2_user_token")
|
||||
public class UserTokenDO {
|
||||
@TableId(type = IdType.AUTO)
|
||||
Integer id;
|
||||
String name;
|
||||
String userName;
|
||||
Long expireTime;
|
||||
String token;
|
||||
String salt;
|
||||
Date createTime;
|
||||
Date updateTime;
|
||||
String createBy;
|
||||
String updateBy;
|
||||
Date expireDateTime;
|
||||
}
|
||||
@@ -14,4 +14,6 @@ public interface UserDOMapper {
|
||||
|
||||
/** @mbg.generated */
|
||||
List<UserDO> selectByExample(UserDOExample example);
|
||||
|
||||
void updateByPrimaryKey(UserDO userDO);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.tencent.supersonic.auth.authentication.persistence.mapper;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserTokenDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface UserTokenDOMapper extends BaseMapper<UserTokenDO> {
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.tencent.supersonic.auth.authentication.persistence.repository;
|
||||
|
||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserTokenDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -10,5 +11,17 @@ public interface UserRepository {
|
||||
|
||||
void addUser(UserDO userDO);
|
||||
|
||||
List<UserTokenDO> getUserTokenListByName(String userName);
|
||||
|
||||
UserDO getUser(String name);
|
||||
|
||||
void updateUser(UserDO userDO);
|
||||
|
||||
void addUserToken(UserTokenDO userTokenDO);
|
||||
|
||||
UserTokenDO getUserToken(Long tokenId);
|
||||
|
||||
void deleteUserTokenByName(String userName);
|
||||
|
||||
void deleteUserToken(Long tokenId);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.tencent.supersonic.auth.authentication.persistence.repository.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDOExample;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserTokenDO;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.mapper.UserDOMapper;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.mapper.UserTokenDOMapper;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.repository.UserRepository;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -14,8 +17,11 @@ public class UserRepositoryImpl implements UserRepository {
|
||||
|
||||
private UserDOMapper userDOMapper;
|
||||
|
||||
public UserRepositoryImpl(UserDOMapper userDOMapper) {
|
||||
private UserTokenDOMapper userTokenDOMapper;
|
||||
|
||||
public UserRepositoryImpl(UserDOMapper userDOMapper, UserTokenDOMapper userTokenDOMapper) {
|
||||
this.userDOMapper = userDOMapper;
|
||||
this.userTokenDOMapper = userTokenDOMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -23,6 +29,11 @@ public class UserRepositoryImpl implements UserRepository {
|
||||
return userDOMapper.selectByExample(new UserDOExample());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUser(UserDO userDO) {
|
||||
userDOMapper.updateByPrimaryKey(userDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUser(UserDO userDO) {
|
||||
userDOMapper.insert(userDO);
|
||||
@@ -36,4 +47,33 @@ public class UserRepositoryImpl implements UserRepository {
|
||||
Optional<UserDO> userDOOptional = userDOS.stream().findFirst();
|
||||
return userDOOptional.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserTokenDO> getUserTokenListByName(String userName) {
|
||||
QueryWrapper<UserTokenDO> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("user_name", userName);
|
||||
return userTokenDOMapper.selectList(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUserToken(UserTokenDO userTokenDO) {
|
||||
userTokenDOMapper.insert(userTokenDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserTokenDO getUserToken(Long tokenId) {
|
||||
return userTokenDOMapper.selectById(tokenId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUserTokenByName(String userName) {
|
||||
QueryWrapper<UserTokenDO> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("user_name", userName);
|
||||
userTokenDOMapper.delete(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUserToken(Long tokenId) {
|
||||
userTokenDOMapper.deleteById(tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
||||
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
||||
import com.tencent.supersonic.auth.api.authentication.request.UserTokenReq;
|
||||
import com.tencent.supersonic.auth.api.authentication.service.UserService;
|
||||
import com.tencent.supersonic.common.pojo.User;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -13,6 +15,7 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
@@ -69,4 +72,28 @@ public class UserController {
|
||||
public String login(@RequestBody UserReq userCmd, HttpServletRequest request) {
|
||||
return userService.login(userCmd, request);
|
||||
}
|
||||
|
||||
@PostMapping("/generateToken")
|
||||
public UserToken generateToken(@RequestBody UserTokenReq userTokenReq,
|
||||
HttpServletRequest request, HttpServletResponse response) {
|
||||
User user = userService.getCurrentUser(request, response);
|
||||
return userService.generateToken(userTokenReq.getName(), user.getName(),
|
||||
userTokenReq.getExpireTime());
|
||||
}
|
||||
|
||||
@GetMapping("/getUserTokens")
|
||||
public List<UserToken> getUserTokens(HttpServletRequest request, HttpServletResponse response) {
|
||||
User user = userService.getCurrentUser(request, response);
|
||||
return userService.getUserTokens(user.getName());
|
||||
}
|
||||
|
||||
@GetMapping("/getUserToken")
|
||||
public UserToken getUserToken(@RequestParam(name = "tokenId") Long tokenId) {
|
||||
return userService.getUserToken(tokenId);
|
||||
}
|
||||
|
||||
@PostMapping("/deleteUserToken")
|
||||
public void deleteUserToken(@RequestParam(name = "tokenId") Long tokenId) {
|
||||
userService.deleteUserToken(tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.Organization;
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserToken;
|
||||
import com.tencent.supersonic.auth.api.authentication.request.UserReq;
|
||||
import com.tencent.supersonic.auth.api.authentication.service.UserService;
|
||||
import com.tencent.supersonic.auth.api.authentication.utils.UserHolder;
|
||||
@@ -79,4 +80,34 @@ public class UserServiceImpl implements UserService {
|
||||
public String login(UserReq userReq, String appKey) {
|
||||
return ComponentFactory.getUserAdaptor().login(userReq, appKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword(String userName) {
|
||||
return ComponentFactory.getUserAdaptor().getPassword(userName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPassword(String userName, String password, String newPassword) {
|
||||
ComponentFactory.getUserAdaptor().resetPassword(userName, password, newPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserToken generateToken(String name, String userName, long expireTime) {
|
||||
return ComponentFactory.getUserAdaptor().generateToken(name, userName, expireTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserToken> getUserTokens(String userName) {
|
||||
return ComponentFactory.getUserAdaptor().getUserTokens(userName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserToken getUserToken(Long id) {
|
||||
return ComponentFactory.getUserAdaptor().getUserToken(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUserToken(Long id) {
|
||||
ComponentFactory.getUserAdaptor().deleteUserToken(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.tencent.supersonic.auth.authentication.strategy;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.constant.UserConstants;
|
||||
import com.tencent.supersonic.auth.api.authentication.service.UserStrategy;
|
||||
import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
||||
@@ -7,8 +10,6 @@ import com.tencent.supersonic.common.pojo.User;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.tencent.supersonic.auth.authentication.utils;
|
||||
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
|
||||
import com.tencent.supersonic.common.pojo.exception.AccessException;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
@@ -9,14 +13,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_CREATE_TIME;
|
||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_PREFIX;
|
||||
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_NAME;
|
||||
|
||||
@@ -32,33 +33,40 @@ public class TokenService {
|
||||
|
||||
public String generateToken(Map<String, Object> claims, HttpServletRequest request) {
|
||||
String appKey = getAppKey(request);
|
||||
return generateToken(claims, appKey);
|
||||
long expiration = System.currentTimeMillis() + authenticationConfig.getTokenTimeout();
|
||||
return generateToken(claims, appKey, expiration);
|
||||
}
|
||||
|
||||
public String generateToken(Map<String, Object> claims, long expiration) {
|
||||
String appKey = authenticationConfig.getTokenDefaultAppKey();
|
||||
long exp = System.currentTimeMillis() + expiration;
|
||||
return generateToken(claims, appKey, exp);
|
||||
}
|
||||
|
||||
public String generateToken(Map<String, Object> claims, String appKey) {
|
||||
return toTokenString(claims, appKey);
|
||||
long expiration = System.currentTimeMillis() + authenticationConfig.getTokenTimeout();
|
||||
return toTokenString(claims, appKey, expiration);
|
||||
}
|
||||
|
||||
private String toTokenString(Map<String, Object> claims, String appKey) {
|
||||
Long tokenTimeout = authenticationConfig.getTokenTimeout();
|
||||
long expiration = Long.parseLong(claims.get(TOKEN_CREATE_TIME) + "") + tokenTimeout;
|
||||
Date expirationDate = new Date(expiration);
|
||||
String tokenSecret = getTokenSecret(appKey);
|
||||
|
||||
return Jwts.builder().setClaims(claims).setSubject(claims.get(TOKEN_USER_NAME).toString())
|
||||
.setExpiration(expirationDate)
|
||||
.signWith(new SecretKeySpec(tokenSecret.getBytes(StandardCharsets.UTF_8),
|
||||
SignatureAlgorithm.HS512.getJcaName()), SignatureAlgorithm.HS512)
|
||||
.compact();
|
||||
public String generateToken(Map<String, Object> claims, String appKey, long expiration) {
|
||||
return toTokenString(claims, appKey, expiration);
|
||||
}
|
||||
|
||||
private String getTokenSecret(String appKey) {
|
||||
Map<String, String> appKeyToSecretMap = authenticationConfig.getAppKeyToSecretMap();
|
||||
String secret = appKeyToSecretMap.get(appKey);
|
||||
if (StringUtils.isBlank(secret)) {
|
||||
throw new AccessException("get secret from appKey failed :" + appKey);
|
||||
public String generateAppUserToken(HttpServletRequest request) {
|
||||
String appName = request.getHeader("AppId");
|
||||
if (StringUtils.isBlank(appName)) {
|
||||
String message = "AppId is blank, get app_user failed";
|
||||
log.warn("{}, uri: {}", message, request.getServletPath());
|
||||
throw new AccessException(message);
|
||||
}
|
||||
return secret;
|
||||
|
||||
UserWithPassword appUser = new UserWithPassword(appName);
|
||||
appUser.setId(1L);
|
||||
appUser.setName(appName);
|
||||
appUser.setPassword("c3VwZXJzb25pY0BiaWNvbdktJJYWw6A3rEmBUPzbn/6DNeYnD+y3mAwDKEMS3KVT");
|
||||
appUser.setDisplayName(appName);
|
||||
appUser.setIsAdmin(0);
|
||||
return generateToken(UserWithPassword.convert(appUser), request);
|
||||
}
|
||||
|
||||
public Optional<Claims> getClaims(HttpServletRequest request) {
|
||||
@@ -67,6 +75,17 @@ public class TokenService {
|
||||
return getClaims(token, appKey);
|
||||
}
|
||||
|
||||
private Optional<Claims> getClaims(String token, HttpServletRequest request) {
|
||||
Optional<Claims> claims;
|
||||
try {
|
||||
String appKey = getAppKey(request);
|
||||
claims = getClaims(token, appKey);
|
||||
} catch (Exception e) {
|
||||
throw new AccessException("parse user info from token failed :" + token);
|
||||
}
|
||||
return claims;
|
||||
}
|
||||
|
||||
public Optional<Claims> getClaims(String token, String appKey) {
|
||||
try {
|
||||
String tokenSecret = getTokenSecret(appKey);
|
||||
@@ -86,6 +105,26 @@ public class TokenService {
|
||||
: token.trim();
|
||||
}
|
||||
|
||||
private String toTokenString(Map<String, Object> claims, String appKey, long expiration) {
|
||||
Date expirationDate = new Date(expiration);
|
||||
String tokenSecret = getTokenSecret(appKey);
|
||||
|
||||
return Jwts.builder().setClaims(claims).setSubject(claims.get(TOKEN_USER_NAME).toString())
|
||||
.setExpiration(expirationDate)
|
||||
.signWith(new SecretKeySpec(tokenSecret.getBytes(StandardCharsets.UTF_8),
|
||||
SignatureAlgorithm.HS512.getJcaName()), SignatureAlgorithm.HS512)
|
||||
.compact();
|
||||
}
|
||||
|
||||
private String getTokenSecret(String appKey) {
|
||||
Map<String, String> appKeyToSecretMap = authenticationConfig.getAppKeyToSecretMap();
|
||||
String secret = appKeyToSecretMap.get(appKey);
|
||||
if (StringUtils.isBlank(secret)) {
|
||||
throw new AccessException("get secret from appKey failed :" + appKey);
|
||||
}
|
||||
return secret;
|
||||
}
|
||||
|
||||
public String getAppKey(HttpServletRequest request) {
|
||||
String appKey = request.getHeader(authenticationConfig.getTokenHttpHeaderAppKey());
|
||||
if (StringUtils.isBlank(appKey)) {
|
||||
@@ -93,4 +132,8 @@ public class TokenService {
|
||||
}
|
||||
return appKey;
|
||||
}
|
||||
|
||||
public String getDefaultAppKey() {
|
||||
return authenticationConfig.getTokenDefaultAppKey();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,4 +122,29 @@
|
||||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<update id="updateByPrimaryKey" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO">
|
||||
update s2_user
|
||||
<set>
|
||||
<if test="name != null">
|
||||
name = #{name,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="password != null">
|
||||
password = #{password,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="salt != null">
|
||||
salt = #{salt,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="displayName != null">
|
||||
display_name = #{displayName,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="email != null">
|
||||
email = #{email,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="isAdmin != null">
|
||||
is_admin = #{isAdmin,jdbcType=INTEGER},
|
||||
</if>
|
||||
</set>
|
||||
where id = #{id,jdbcType=BIGINT}
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.tencent.supersonic.auth.authentication.persistence.mapper.UserTokenDOMapper">
|
||||
<resultMap id="BaseResultMap" type="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserTokenDO">
|
||||
<result column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="name" jdbcType="VARCHAR" property="name" />
|
||||
<result column="token" jdbcType="VARCHAR" property="token" />
|
||||
<result column="expire_time" jdbcType="TIMESTAMP" property="expireTime" />
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||
</resultMap>
|
||||
|
||||
|
||||
|
||||
</mapper>
|
||||
@@ -2,8 +2,15 @@ package com.tencent.supersonic.common.pojo;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.tencent.supersonic.common.pojo.Parameter;
|
||||
import dev.langchain4j.provider.*;
|
||||
import dev.langchain4j.provider.AzureModelFactory;
|
||||
import dev.langchain4j.provider.DashscopeModelFactory;
|
||||
import dev.langchain4j.provider.DifyModelFactory;
|
||||
import dev.langchain4j.provider.LocalAiModelFactory;
|
||||
import dev.langchain4j.provider.ModelProvider;
|
||||
import dev.langchain4j.provider.OllamaModelFactory;
|
||||
import dev.langchain4j.provider.OpenAiModelFactory;
|
||||
import dev.langchain4j.provider.QianfanModelFactory;
|
||||
import dev.langchain4j.provider.ZhipuModelFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -52,7 +59,7 @@ public class ChatModelParameters {
|
||||
return Lists.newArrayList(OpenAiModelFactory.PROVIDER, OllamaModelFactory.PROVIDER,
|
||||
QianfanModelFactory.PROVIDER, ZhipuModelFactory.PROVIDER,
|
||||
LocalAiModelFactory.PROVIDER, DashscopeModelFactory.PROVIDER,
|
||||
AzureModelFactory.PROVIDER);
|
||||
AzureModelFactory.PROVIDER, DifyModelFactory.PROVIDER);
|
||||
}
|
||||
|
||||
private static List<Parameter.Dependency> getBaseUrlDependency() {
|
||||
@@ -63,20 +70,23 @@ public class ChatModelParameters {
|
||||
QianfanModelFactory.PROVIDER, QianfanModelFactory.DEFAULT_BASE_URL,
|
||||
ZhipuModelFactory.PROVIDER, ZhipuModelFactory.DEFAULT_BASE_URL,
|
||||
LocalAiModelFactory.PROVIDER, LocalAiModelFactory.DEFAULT_BASE_URL,
|
||||
DashscopeModelFactory.PROVIDER, DashscopeModelFactory.DEFAULT_BASE_URL));
|
||||
DashscopeModelFactory.PROVIDER, DashscopeModelFactory.DEFAULT_BASE_URL,
|
||||
DifyModelFactory.PROVIDER, DifyModelFactory.DEFAULT_BASE_URL));
|
||||
}
|
||||
|
||||
private static List<Parameter.Dependency> getApiKeyDependency() {
|
||||
return getDependency(CHAT_MODEL_PROVIDER.getName(),
|
||||
Lists.newArrayList(OpenAiModelFactory.PROVIDER, QianfanModelFactory.PROVIDER,
|
||||
ZhipuModelFactory.PROVIDER, LocalAiModelFactory.PROVIDER,
|
||||
AzureModelFactory.PROVIDER, DashscopeModelFactory.PROVIDER),
|
||||
AzureModelFactory.PROVIDER, DashscopeModelFactory.PROVIDER,
|
||||
DifyModelFactory.PROVIDER),
|
||||
ImmutableMap.of(OpenAiModelFactory.PROVIDER,
|
||||
ModelProvider.DEMO_CHAT_MODEL.getApiKey(), QianfanModelFactory.PROVIDER,
|
||||
ModelProvider.DEMO_CHAT_MODEL.getApiKey(), ZhipuModelFactory.PROVIDER,
|
||||
ModelProvider.DEMO_CHAT_MODEL.getApiKey(), LocalAiModelFactory.PROVIDER,
|
||||
ModelProvider.DEMO_CHAT_MODEL.getApiKey(), AzureModelFactory.PROVIDER,
|
||||
ModelProvider.DEMO_CHAT_MODEL.getApiKey(), DashscopeModelFactory.PROVIDER,
|
||||
ModelProvider.DEMO_CHAT_MODEL.getApiKey(), DifyModelFactory.PROVIDER,
|
||||
ModelProvider.DEMO_CHAT_MODEL.getApiKey()));
|
||||
}
|
||||
|
||||
@@ -88,7 +98,8 @@ public class ChatModelParameters {
|
||||
ZhipuModelFactory.PROVIDER, ZhipuModelFactory.DEFAULT_MODEL_NAME,
|
||||
LocalAiModelFactory.PROVIDER, LocalAiModelFactory.DEFAULT_MODEL_NAME,
|
||||
AzureModelFactory.PROVIDER, AzureModelFactory.DEFAULT_MODEL_NAME,
|
||||
DashscopeModelFactory.PROVIDER, DashscopeModelFactory.DEFAULT_MODEL_NAME));
|
||||
DashscopeModelFactory.PROVIDER, DashscopeModelFactory.DEFAULT_MODEL_NAME,
|
||||
DifyModelFactory.PROVIDER, DifyModelFactory.DEFAULT_MODEL_NAME));
|
||||
}
|
||||
|
||||
private static List<Parameter.Dependency> getEndpointDependency() {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.tencent.supersonic.common.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Slf4j
|
||||
public class DifyClient {
|
||||
private static final String DEFAULT_USER = "zhaodongsheng";
|
||||
private static final String CONTENT_TYPE_JSON = "application/json";
|
||||
|
||||
private String difyURL;
|
||||
private String difyKey;
|
||||
|
||||
public DifyClient(String difyURL, String difyKey) {
|
||||
this.difyURL = difyURL;
|
||||
this.difyKey = difyKey;
|
||||
}
|
||||
|
||||
public DifyResult generate(String prompt) {
|
||||
Map<String, String> headers = defaultHeaders();
|
||||
DifyRequest request = new DifyRequest();
|
||||
request.setQuery(prompt);
|
||||
request.setUser(DEFAULT_USER);
|
||||
return sendRequest(request, headers);
|
||||
}
|
||||
|
||||
public DifyResult generate(String prompt, String user) {
|
||||
Map<String, String> headers = defaultHeaders();
|
||||
DifyRequest request = new DifyRequest();
|
||||
request.setQuery(prompt);
|
||||
request.setUser(user);
|
||||
return sendRequest(request, headers);
|
||||
}
|
||||
|
||||
public DifyResult generate(Map<String, String> inputs, String queryText, String user,
|
||||
String conversationId) {
|
||||
Map<String, String> headers = defaultHeaders();
|
||||
DifyRequest request = new DifyRequest();
|
||||
request.setInputs(inputs);
|
||||
request.setQuery(queryText);
|
||||
request.setUser(user);
|
||||
if (conversationId != null && !conversationId.isEmpty()) {
|
||||
request.setConversationId(conversationId);
|
||||
}
|
||||
return sendRequest(request, headers);
|
||||
}
|
||||
|
||||
public DifyResult sendRequest(DifyRequest request, Map<String, String> headers) {
|
||||
try {
|
||||
log.debug("请求dify- header--->" + JsonUtil.toString(headers));
|
||||
log.debug("请求dify- conversionId--->" + JsonUtil.toString(request));
|
||||
return HttpUtils.post(difyURL, JsonUtil.toString(request), headers, DifyResult.class);
|
||||
} catch (Exception e) {
|
||||
log.error("请求dify失败---->" + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String parseSQLResult(String sql) {
|
||||
Pattern pattern = Pattern.compile("```(sql)?(.*)```", Pattern.DOTALL);
|
||||
Matcher matcher = pattern.matcher(sql);
|
||||
if (!matcher.find()) {
|
||||
return sql.trim();
|
||||
} else {
|
||||
return matcher.group(2).trim();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> defaultHeaders() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
if (difyKey.contains("Bearer")) {
|
||||
headers.put("Authorization", difyKey);
|
||||
} else {
|
||||
headers.put("Authorization", "Bearer " + difyKey);
|
||||
}
|
||||
|
||||
headers.put("Content-Type", CONTENT_TYPE_JSON);
|
||||
return headers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.tencent.supersonic.common.util;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class DifyRequest {
|
||||
private String query;
|
||||
private Map<String, String> inputs = new HashMap<>();
|
||||
private String responseMode = "blocking";
|
||||
private String user;
|
||||
@JsonProperty("conversation_id")
|
||||
private String conversationId;
|
||||
@JsonProperty("auto_generate_name")
|
||||
private Boolean autoGenerateName = false;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.tencent.supersonic.common.util;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DifyResult {
|
||||
private String event = "";
|
||||
private String taskId = "";
|
||||
private String conversationId = "";
|
||||
private String id = "";
|
||||
private String messageId = "";
|
||||
private String answer = "";
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package com.tencent.supersonic.common.util;
|
||||
|
||||
import okhttp3.Dispatcher;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class HttpUtils {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);
|
||||
|
||||
// 重试参考:okhttp3.RealCall.getResponseWithInterceptorChain
|
||||
private static final OkHttpClient client = new OkHttpClient.Builder()
|
||||
.readTimeout(3, TimeUnit.MINUTES).retryOnConnectionFailure(true).build();
|
||||
|
||||
static {
|
||||
Dispatcher dispatcher = client.dispatcher();
|
||||
dispatcher.setMaxRequestsPerHost(300);
|
||||
dispatcher.setMaxRequests(200);
|
||||
}
|
||||
|
||||
public static Response execute(String url) throws IOException {
|
||||
Request request = new Request.Builder().url(url).build();
|
||||
return client.newCall(request).execute();
|
||||
}
|
||||
|
||||
public static String get(String url) throws IOException {
|
||||
return doRequest(builder(url).build());
|
||||
}
|
||||
|
||||
public static String get(String url, Map<String, String> headers) throws IOException {
|
||||
return doRequest(headerBuilder(url, headers).build());
|
||||
}
|
||||
|
||||
public static String get(String url, Map<String, String> headers, Map<String, Object> params)
|
||||
throws IOException {
|
||||
return doRequest(headerBuilder(url + buildUrlParams(params), headers).build());
|
||||
}
|
||||
|
||||
public static <T> T get(String url, Class<T> classOfT) throws IOException {
|
||||
return doRequest(builder(url).build(), classOfT);
|
||||
}
|
||||
|
||||
public static <T> T get(String url, Map<String, String> headers, Class<T> classOfT)
|
||||
throws IOException {
|
||||
return doRequest(headerBuilder(url, headers).build(), classOfT);
|
||||
}
|
||||
|
||||
public static <T> T get(String url, Map<String, String> headers, Map<String, Object> params,
|
||||
Class<T> classOfT) throws IOException {
|
||||
return doRequest(headerBuilder(url + buildUrlParams(params), headers).build(), classOfT);
|
||||
}
|
||||
|
||||
// public static <T> T get(String url, TypeReference<T> type) throws IOException {
|
||||
// return doRequest(builder(url).build(), type);
|
||||
// }
|
||||
|
||||
// public static <T> T get(String url, Map<String, String> headers, TypeReference<T> type)
|
||||
// throws IOException {
|
||||
// return doRequest(headerBuilder(url, headers).build(), type);
|
||||
// }
|
||||
|
||||
// public static <T> T get(String url, Map<String, String> headers, Map<String, Object> params,
|
||||
// TypeReference<T> type) throws IOException {
|
||||
// return doRequest(headerBuilder(url + buildUrlParams(params), headers).build(), type);
|
||||
// }
|
||||
|
||||
public static String post(String url, Object body) throws IOException {
|
||||
return doRequest(postRequest(url, body));
|
||||
}
|
||||
|
||||
public static String post(String url, Object body, Map<String, String> headers)
|
||||
throws IOException {
|
||||
return doRequest(postRequest(url, body, headers));
|
||||
}
|
||||
|
||||
public static <T> T post(String url, Object body, Class<T> classOfT) throws IOException {
|
||||
return doRequest(postRequest(url, body), classOfT);
|
||||
}
|
||||
|
||||
// public static <T> T post(String url, Object body, TypeReference<T> type) throws IOException {
|
||||
// return doRequest(postRequest(url, body), type);
|
||||
// }
|
||||
|
||||
public static <T> T post(String url, Object body, Map<String, String> headers,
|
||||
Class<T> classOfT) throws IOException {
|
||||
return doRequest(postRequest(url, body, headers), classOfT);
|
||||
}
|
||||
|
||||
// public static <T> T post(String url, Object body, Map<String, String> headers,
|
||||
// TypeReference<T> type) throws IOException {
|
||||
// return doRequest(postRequest(url, body, headers), type);
|
||||
// }
|
||||
|
||||
private static Request postRequest(String url, Object body) {
|
||||
return builder(url).post(buildRequestBody(body, null)).build();
|
||||
}
|
||||
|
||||
private static Request postRequest(String url, Object body, Map<String, String> headers) {
|
||||
return headerBuilder(url, headers).post(buildRequestBody(body, headers)).build();
|
||||
}
|
||||
|
||||
private static Request.Builder builder(String url) {
|
||||
return new Request.Builder().url(url);
|
||||
}
|
||||
|
||||
private static Request.Builder headerBuilder(String url, Map<String, String> headers) {
|
||||
Request.Builder builder = new Request.Builder().url(url);
|
||||
headers.forEach(builder::addHeader);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static <T> T doRequest(Request request, Class<T> classOfT) throws IOException {
|
||||
return JsonUtil.toObject(doRequest(request), classOfT);
|
||||
}
|
||||
|
||||
// private static <T> T doRequest(Request request, TypeReference<T> type) throws IOException {
|
||||
// return JsonUtil.toObject(doRequest(request), type);
|
||||
// }
|
||||
|
||||
private static String doRequest(Request request) throws IOException {
|
||||
long beginTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
Response response = client.newCall(request).execute();
|
||||
if (response.isSuccessful()) {
|
||||
return response.body().string();
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Http请求失败[" + response.code() + "]:" + response.body().string() + "...");
|
||||
}
|
||||
} finally {
|
||||
logger.info("begin to request : {}, execute costs(ms) : {}", request.url(),
|
||||
System.currentTimeMillis() - beginTime);
|
||||
}
|
||||
}
|
||||
|
||||
private static RequestBody buildRequestBody(Object body, Map<String, String> headers) {
|
||||
if (headers != null && headers.containsKey("Content-Type")) {
|
||||
String contentType = headers.get("Content-Type");
|
||||
return RequestBody.create(MediaType.parse(contentType), body.toString());
|
||||
}
|
||||
|
||||
if (body instanceof String && ((String) body).contains("=")) {
|
||||
return RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"),
|
||||
(String) body);
|
||||
}
|
||||
|
||||
return RequestBody.create(MediaType.parse("application/json"), JsonUtil.toString(body));
|
||||
}
|
||||
|
||||
private static String buildUrlParams(Map<String, Object> params) {
|
||||
if (params.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return "?" + params.entrySet().stream().map(it -> it.getKey() + "=" + it.getValue())
|
||||
.collect(Collectors.joining("&"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package dev.langchain4j.model.dify;
|
||||
|
||||
import com.tencent.supersonic.common.util.AESEncryptionUtil;
|
||||
import com.tencent.supersonic.common.util.DifyClient;
|
||||
import com.tencent.supersonic.common.util.DifyResult;
|
||||
import dev.langchain4j.agent.tool.ToolSpecification;
|
||||
import dev.langchain4j.data.message.AiMessage;
|
||||
import dev.langchain4j.data.message.ChatMessage;
|
||||
import dev.langchain4j.model.chat.ChatLanguageModel;
|
||||
import dev.langchain4j.model.output.Response;
|
||||
import lombok.Builder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static dev.langchain4j.internal.Utils.getOrDefault;
|
||||
import static dev.langchain4j.internal.Utils.isNullOrEmpty;
|
||||
import static dev.langchain4j.internal.ValidationUtils.ensureNotEmpty;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
public class DifyAiChatModel implements ChatLanguageModel {
|
||||
|
||||
private static final String CONTENT_TYPE_JSON = "application/json";
|
||||
|
||||
private final String baseUrl;
|
||||
private final String apiKey;
|
||||
|
||||
private final DifyClient difyClient;
|
||||
private final Integer maxRetries;
|
||||
private final Integer maxToken;
|
||||
|
||||
private final String appName;
|
||||
private final Double temperature;
|
||||
private final Long timeOut;
|
||||
|
||||
private String userName;
|
||||
|
||||
@Builder
|
||||
public DifyAiChatModel(String baseUrl, String apiKey, Integer maxRetries, Integer maxToken,
|
||||
String modelName, Double temperature, Long timeOut) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.maxRetries = getOrDefault(maxRetries, 3);
|
||||
this.maxToken = getOrDefault(maxToken, 512);
|
||||
try {
|
||||
this.apiKey = AESEncryptionUtil.aesDecryptECB(apiKey);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.appName = modelName;
|
||||
this.temperature = temperature;
|
||||
this.timeOut = timeOut;
|
||||
this.difyClient = new DifyClient(this.baseUrl, this.apiKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generate(String message) {
|
||||
DifyResult difyResult = this.difyClient.generate(message, this.getUserName());
|
||||
return difyResult.getAnswer().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<AiMessage> generate(List<ChatMessage> messages) {
|
||||
return generate(messages, (ToolSpecification) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<AiMessage> generate(List<ChatMessage> messages,
|
||||
List<ToolSpecification> toolSpecifications) {
|
||||
ensureNotEmpty(messages, "messages");
|
||||
DifyResult difyResult =
|
||||
this.difyClient.generate(messages.get(0).text(), this.getUserName());
|
||||
System.out.println(difyResult.toString());
|
||||
|
||||
if (!isNullOrEmpty(toolSpecifications)) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
return Response.from(AiMessage.from(difyResult.getAnswer()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<AiMessage> generate(List<ChatMessage> messages,
|
||||
ToolSpecification toolSpecification) {
|
||||
return generate(messages,
|
||||
toolSpecification != null ? singletonList(toolSpecification) : null);
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return null == userName ? "zhaodongsheng" : userName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package dev.langchain4j.provider;
|
||||
|
||||
import com.tencent.supersonic.common.pojo.ChatModelConfig;
|
||||
import com.tencent.supersonic.common.pojo.EmbeddingModelConfig;
|
||||
import com.tencent.supersonic.common.util.AESEncryptionUtil;
|
||||
import dev.langchain4j.model.chat.ChatLanguageModel;
|
||||
import dev.langchain4j.model.dify.DifyAiChatModel;
|
||||
import dev.langchain4j.model.embedding.EmbeddingModel;
|
||||
import dev.langchain4j.model.zhipu.ZhipuAiEmbeddingModel;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class DifyModelFactory implements ModelFactory, InitializingBean {
|
||||
public static final String PROVIDER = "DIFY";
|
||||
|
||||
public static final String DEFAULT_BASE_URL = "https://dify.com/v1/chat-messages";
|
||||
public static final String DEFAULT_MODEL_NAME = "demo-预留-可不填写";
|
||||
public static final String DEFAULT_EMBEDDING_MODEL_NAME = "all-minilm";
|
||||
|
||||
@Override
|
||||
public ChatLanguageModel createChatModel(ChatModelConfig modelConfig) {
|
||||
return DifyAiChatModel.builder().baseUrl(modelConfig.getBaseUrl())
|
||||
.apiKey(AESEncryptionUtil.aesDecryptECB(modelConfig.getApiKey()))
|
||||
.modelName(modelConfig.getModelName()).timeOut(modelConfig.getTimeOut()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddingModel createEmbeddingModel(EmbeddingModelConfig embeddingModelConfig) {
|
||||
return ZhipuAiEmbeddingModel.builder().baseUrl(embeddingModelConfig.getBaseUrl())
|
||||
.apiKey(embeddingModelConfig.getApiKey()).model(embeddingModelConfig.getModelName())
|
||||
.maxRetries(embeddingModelConfig.getMaxRetries())
|
||||
.logRequests(embeddingModelConfig.getLogRequests())
|
||||
.logResponses(embeddingModelConfig.getLogResponses()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
ModelProvider.add(PROVIDER, this);
|
||||
}
|
||||
}
|
||||
@@ -682,3 +682,19 @@ CREATE TABLE IF NOT EXISTS `s2_term` (
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
COMMENT ON TABLE s2_term IS 'term info';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `s2_user_token` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`user_name` VARCHAR(255) NOT NULL,
|
||||
`expire_time` INT NOT NULL,
|
||||
`token` text NOT NULL,
|
||||
`salt` VARCHAR(255) default NULL,
|
||||
`create_time` DATETIME NOT NULL,
|
||||
`create_by` VARCHAR(255) NOT NULL,
|
||||
`update_time` DATETIME default NULL,
|
||||
`update_by` VARCHAR(255) NOT NULL,
|
||||
`expire_date_time` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
COMMENT ON TABLE s2_user_token IS 'user token info';
|
||||
|
||||
@@ -603,3 +603,19 @@ CREATE TABLE IF NOT EXISTS `s2_term` (
|
||||
`updated_by` varchar(100) DEFAULT NULL ,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8 COMMENT ='术语表';
|
||||
|
||||
CREATE TABLE `s2_user_token` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`user_name` VARCHAR(255) NOT NULL,
|
||||
`expire_time` BIGINT(20) NOT NULL,
|
||||
`token` text NOT NULL,
|
||||
`salt` VARCHAR(255) default NULL,
|
||||
`create_time` DATETIME NOT NULL,
|
||||
`create_by` VARCHAR(255) NOT NULL,
|
||||
`update_time` DATETIME default NULL,
|
||||
`update_by` VARCHAR(255) NOT NULL,
|
||||
`expire_date_time` DATETIME NOT NULL,
|
||||
unique key name_username (`name`, `user_name`),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin comment='用户令牌信息表';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export default {
|
||||
dev: {
|
||||
'/api/': {
|
||||
target: 'http://10.91.217.39:9080',
|
||||
target: 'http://127.0.0.1:9080',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
||||
import { Button, Form, Input, message, Modal, Table } from 'antd';
|
||||
import { useBoolean, useDynamicList, useRequest } from 'ahooks';
|
||||
import {
|
||||
changePassword,
|
||||
generateAccessToken,
|
||||
getUserAccessTokens,
|
||||
removeAccessToken,
|
||||
} from '@/services/user';
|
||||
import { encryptPassword, encryptKey } from '@/utils/utils';
|
||||
import { API } from '@/services/API';
|
||||
import { EditableProTable, ProColumns } from '@ant-design/pro-components';
|
||||
import { CopyOutlined } from '@ant-design/icons';
|
||||
|
||||
type DataSourceType = {
|
||||
id: React.Key;
|
||||
name?: string;
|
||||
token?: string;
|
||||
expireDate?: string;
|
||||
createDate?: string;
|
||||
toBeSaved?: boolean;
|
||||
};
|
||||
|
||||
export interface IRef {
|
||||
open: () => void;
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
const ChangePasswordModal = forwardRef<IRef>((_, ref) => {
|
||||
const [open, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
|
||||
const [dataSource, setDataSource] = useState<readonly DataSourceType[]>([]);
|
||||
|
||||
const getAccessTokens = async () => {
|
||||
try {
|
||||
const res = await getUserAccessTokens();
|
||||
if (res && res.code === 200) {
|
||||
return res.data;
|
||||
} else {
|
||||
message.error(res.msg);
|
||||
return [];
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('获取数据失败,原因:' + error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => {
|
||||
openModal();
|
||||
},
|
||||
close: () => {
|
||||
closeModal();
|
||||
},
|
||||
}));
|
||||
|
||||
const columns: ProColumns<DataSourceType>[] = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
width: '15%',
|
||||
formItemProps: {
|
||||
rules: [{ required: true, message: '此项为必填项' }],
|
||||
},
|
||||
editable: (text, record, index) => !!record.toBeSaved,
|
||||
},
|
||||
{
|
||||
title: '访问令牌',
|
||||
dataIndex: 'token',
|
||||
width: '25%',
|
||||
formItemProps: (form, { rowIndex }) => {
|
||||
return {
|
||||
rules: [{ required: true, message: '此项为必填项' }],
|
||||
};
|
||||
},
|
||||
render: (text, record, index) => {
|
||||
// 脱敏处理, 点击图标可完整token
|
||||
return record.toBeSaved ? (
|
||||
text
|
||||
) : (
|
||||
<>
|
||||
{record.token ? record.token.slice(0, 5) + '********' + record.token.slice(-5) : ''}
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(record.token || '');
|
||||
message.info('已复制到剪贴板');
|
||||
}}
|
||||
>
|
||||
<CopyOutlined />
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
},
|
||||
editable: false,
|
||||
},
|
||||
{
|
||||
title: '过期时间',
|
||||
dataIndex: 'expireDate',
|
||||
valueType: 'date',
|
||||
width: '20%',
|
||||
formItemProps: {
|
||||
rules: [{ required: true, message: '此项为必填项' }],
|
||||
},
|
||||
editable: (text, record, index) => !!record.toBeSaved,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createDate',
|
||||
valueType: 'date',
|
||||
editable: false,
|
||||
width: '20%',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: '15%',
|
||||
render: (text, record, _, action) => [
|
||||
<a
|
||||
key="delete"
|
||||
onClick={() => {
|
||||
Modal.confirm({
|
||||
title: '删除访问令牌',
|
||||
content: '确定删除此访问令牌吗?',
|
||||
onOk: async () => {
|
||||
const res = await removeAccessToken(record.id as number);
|
||||
|
||||
if (res && res.code !== 200) {
|
||||
message.error('删除失败,原因:' + res.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
setDataSource(dataSource.filter((item) => item.id !== record.id));
|
||||
message.success('删除成功');
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
删除
|
||||
</a>,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="访问令牌"
|
||||
open={open}
|
||||
onClose={closeModal}
|
||||
onCancel={closeModal}
|
||||
width={1200}
|
||||
footer={false}
|
||||
destroyOnClose
|
||||
>
|
||||
<EditableProTable<DataSourceType>
|
||||
rowKey="id"
|
||||
recordCreatorProps={{
|
||||
position: 'bottom',
|
||||
creatorButtonText: '新增访问令牌',
|
||||
record: () => ({ id: (Math.random() * 1000000).toFixed(0), toBeSaved: true }),
|
||||
}}
|
||||
loading={false}
|
||||
columns={columns}
|
||||
request={async () => {
|
||||
const data = await getAccessTokens();
|
||||
return {
|
||||
data,
|
||||
total: data.length,
|
||||
success: true,
|
||||
};
|
||||
}}
|
||||
value={dataSource}
|
||||
onChange={setDataSource}
|
||||
editable={{
|
||||
type: 'single',
|
||||
onSave: async (rowKey, data, row) => {
|
||||
console.log(rowKey, data, row);
|
||||
await generateAccessToken({
|
||||
name: data.name!,
|
||||
expireTime: new Date(data.expireDate!).getTime() - new Date().getTime(),
|
||||
});
|
||||
|
||||
const newTokens = await getAccessTokens();
|
||||
setTimeout(() => {
|
||||
setDataSource(newTokens);
|
||||
}, 100);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
});
|
||||
|
||||
export default ChangePasswordModal;
|
||||
@@ -1,10 +1,12 @@
|
||||
import React from 'react';
|
||||
import { LogoutOutlined } from '@ant-design/icons';
|
||||
import React, { useRef } from 'react';
|
||||
import { LogoutOutlined, KeyOutlined, UnlockOutlined } from '@ant-design/icons';
|
||||
import { useModel } from 'umi';
|
||||
import HeaderDropdown from '../HeaderDropdown';
|
||||
import styles from './index.less';
|
||||
import TMEAvatar from '../TMEAvatar';
|
||||
import { AUTH_TOKEN_KEY } from '@/common/constants';
|
||||
import ChangePasswordModal, { IRef as IRefChangePasswordModal } from './ChangePasswordModal';
|
||||
import AccessTokensModal, { IRef as IAccessTokensModalRef } from './AccessTokensModal';
|
||||
import { history } from 'umi';
|
||||
|
||||
export type GlobalHeaderRightProps = {
|
||||
@@ -27,7 +29,38 @@ const { APP_TARGET } = process.env;
|
||||
const AvatarDropdown: React.FC<GlobalHeaderRightProps> = () => {
|
||||
const { initialState = {}, setInitialState } = useModel('@@initialState');
|
||||
const { currentUser = {} } = initialState as any;
|
||||
const changePasswordModalRef = useRef<IRefChangePasswordModal>(null);
|
||||
const accessTokensModalRef = useRef<IAccessTokensModalRef>(null);
|
||||
|
||||
const handleAccessToken = () => {
|
||||
accessTokensModalRef.current?.open();
|
||||
};
|
||||
|
||||
const handleChangePassword = () => {
|
||||
changePasswordModalRef.current?.open();
|
||||
};
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: (
|
||||
<>
|
||||
<KeyOutlined />
|
||||
访问令牌
|
||||
</>
|
||||
),
|
||||
key: 'accessToken',
|
||||
onClick: handleAccessToken,
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<>
|
||||
<UnlockOutlined />
|
||||
修改密码
|
||||
</>
|
||||
),
|
||||
key: 'changePassword',
|
||||
onClick: handleChangePassword,
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<>
|
||||
@@ -48,12 +81,21 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = () => {
|
||||
},
|
||||
];
|
||||
return (
|
||||
<HeaderDropdown menu={{ items }} disabled={APP_TARGET === 'inner'}>
|
||||
<span className={`${styles.action} ${styles.account}`}>
|
||||
<TMEAvatar className={styles.avatar} size="small" staffName={currentUser.staffName} />
|
||||
<span className={styles.userName}>{currentUser.staffName}</span>
|
||||
</span>
|
||||
</HeaderDropdown>
|
||||
<>
|
||||
<HeaderDropdown
|
||||
menu={{
|
||||
items,
|
||||
}}
|
||||
disabled={APP_TARGET === 'inner'}
|
||||
>
|
||||
<span className={`${styles.action} ${styles.account}`}>
|
||||
<TMEAvatar className={styles.avatar} size="small" staffName={currentUser.staffName} />
|
||||
<span className={styles.userName}>{currentUser.staffName}</span>
|
||||
</span>
|
||||
</HeaderDropdown>
|
||||
<ChangePasswordModal ref={changePasswordModalRef} />
|
||||
<AccessTokensModal ref={accessTokensModalRef} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
import React, { forwardRef, useImperativeHandle } from 'react';
|
||||
import { Form, Input, message, Modal } from 'antd';
|
||||
import { useBoolean } from 'ahooks';
|
||||
import { changePassword } from '@/services/user';
|
||||
import { pick } from 'lodash';
|
||||
import { encryptPassword, encryptKey } from '@/utils/utils';
|
||||
|
||||
export interface IRef {
|
||||
open: () => void;
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
const ChangePasswordModal = forwardRef<IRef>((_, ref) => {
|
||||
const [form] = Form.useForm();
|
||||
const [open, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
|
||||
const [confirmLoading, { set: setConfirmLoading }] = useBoolean(false);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => {
|
||||
openModal();
|
||||
form.resetFields();
|
||||
},
|
||||
close: () => {
|
||||
closeModal();
|
||||
form.resetFields();
|
||||
},
|
||||
}));
|
||||
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
console.log(values);
|
||||
setConfirmLoading(true);
|
||||
// Call API to change password
|
||||
const res = await changePassword({
|
||||
oldPassword: encryptPassword(values.oldPassword, encryptKey),
|
||||
newPassword: encryptPassword(values.newPassword, encryptKey),
|
||||
});
|
||||
|
||||
if (res && res.code !== 200) {
|
||||
return message.warning(res.msg);
|
||||
}
|
||||
closeModal();
|
||||
} catch (error) {
|
||||
console.log('Failed:', error);
|
||||
} finally {
|
||||
setConfirmLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="修改密码"
|
||||
open={open}
|
||||
onOk={handleOk}
|
||||
onClose={closeModal}
|
||||
onCancel={closeModal}
|
||||
confirmLoading={confirmLoading}
|
||||
>
|
||||
<Form form={form}>
|
||||
<Form.Item
|
||||
name="oldPassword"
|
||||
label="原密码"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入原密码!',
|
||||
},
|
||||
]}
|
||||
hasFeedback
|
||||
>
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="newPassword"
|
||||
label="新密码"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入新密码!',
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 10,
|
||||
message: '密码须在6-10字符之间!',
|
||||
},
|
||||
]}
|
||||
hasFeedback
|
||||
>
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="confirm"
|
||||
label="确认密码"
|
||||
dependencies={['newPassword']}
|
||||
hasFeedback
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请确认密码!',
|
||||
},
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (!value || getFieldValue('newPassword') === value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(new Error('两次输入的密码不一致!'));
|
||||
},
|
||||
}),
|
||||
]}
|
||||
>
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
});
|
||||
|
||||
export default ChangePasswordModal;
|
||||
@@ -23,6 +23,23 @@ declare namespace API {
|
||||
access?: 'user' | 'guest' | 'admin';
|
||||
};
|
||||
|
||||
export interface UserItem {
|
||||
id: number;
|
||||
name: string;
|
||||
displayName: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface UserAccessToken {
|
||||
createDate: string;
|
||||
expireDate: string;
|
||||
expireTime: number;
|
||||
id: number;
|
||||
name: string;
|
||||
token: string;
|
||||
userName: string;
|
||||
}
|
||||
|
||||
export type LoginStateType = {
|
||||
status?: 'ok' | 'error';
|
||||
type?: string;
|
||||
|
||||
@@ -20,3 +20,31 @@ export function saveSystemConfig(data: any): Promise<any> {
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function changePassword(data: { newPassword: string; oldPassword: string }): Promise<any> {
|
||||
return request(`${process.env.AUTH_API_BASE_URL}user/resetPassword`, {
|
||||
method: 'post',
|
||||
data: {
|
||||
newPassword: data.newPassword,
|
||||
password: data.oldPassword,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 获取用户accessTokens
|
||||
export async function getUserAccessTokens(): Promise<Result<API.UserItem[]>> {
|
||||
return request.get(`${process.env.AUTH_API_BASE_URL}user/getUserTokens`);
|
||||
}
|
||||
|
||||
export function generateAccessToken(data: { expireTime: number; name: string }): Promise<any> {
|
||||
return request(`${process.env.AUTH_API_BASE_URL}user/generateToken`, {
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function removeAccessToken(id: number): Promise<any> {
|
||||
return request(`${process.env.AUTH_API_BASE_URL}user/deleteUserToken?tokenId=${id}`, {
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ export const objToArray = (_obj: ObjToArrayParams, keyType: string = 'string') =
|
||||
});
|
||||
};
|
||||
|
||||
const encryptKey = CryptoJS.enc.Hex.parse(
|
||||
export const encryptKey = CryptoJS.enc.Hex.parse(
|
||||
'9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08',
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user