package cc.mrbird.febs.auth.service.impl;
|
|
import cc.mrbird.febs.auth.entity.BindUser;
|
import cc.mrbird.febs.auth.entity.UserConnection;
|
import cc.mrbird.febs.auth.manager.UserManager;
|
import cc.mrbird.febs.auth.properties.FebsAuthProperties;
|
import cc.mrbird.febs.auth.service.SocialLoginService;
|
import cc.mrbird.febs.auth.service.UserConnectionService;
|
import cc.mrbird.febs.common.core.entity.FebsResponse;
|
import cc.mrbird.febs.common.core.entity.constant.GrantTypeConstant;
|
import cc.mrbird.febs.common.core.entity.constant.ParamsConstant;
|
import cc.mrbird.febs.common.core.entity.constant.SocialConstant;
|
import cc.mrbird.febs.common.core.entity.constant.StringConstant;
|
import cc.mrbird.febs.common.core.entity.system.SystemUser;
|
import cc.mrbird.febs.common.core.exception.FebsException;
|
import cc.mrbird.febs.common.core.utils.FebsUtil;
|
import cn.hutool.core.util.StrUtil;
|
import com.xkcoding.justauth.AuthRequestFactory;
|
import lombok.RequiredArgsConstructor;
|
import me.zhyd.oauth.config.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
import me.zhyd.oauth.model.AuthResponse;
|
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.request.AuthRequest;
|
import org.apache.commons.lang3.StringUtils;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
import org.springframework.security.oauth2.provider.ClientDetails;
|
import org.springframework.security.oauth2.provider.TokenRequest;
|
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
|
import org.springframework.stereotype.Service;
|
|
import javax.servlet.http.HttpServletRequest;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
/**
|
* @author MrBird
|
*/
|
@Service
|
@RequiredArgsConstructor
|
public class SocialLoginServiceImpl implements SocialLoginService {
|
|
private static final String USERNAME = "username";
|
private static final String PASSWORD = "password";
|
|
private static final String NOT_BIND = "not_bind";
|
private static final String SOCIAL_LOGIN_SUCCESS = "social_login_success";
|
|
private final UserManager userManager;
|
private final AuthRequestFactory factory;
|
private final FebsAuthProperties properties;
|
private final PasswordEncoder passwordEncoder;
|
private final UserConnectionService userConnectionService;
|
private final ResourceOwnerPasswordTokenGranter granter;
|
private final RedisClientDetailsService redisClientDetailsService;
|
|
@Override
|
public AuthRequest renderAuth(String oauthType) throws FebsException {
|
return factory.get(getAuthSource(oauthType));
|
}
|
|
@Override
|
public FebsResponse resolveBind(String oauthType, AuthCallback callback) throws FebsException {
|
FebsResponse febsResponse = new FebsResponse();
|
AuthRequest authRequest = factory.get(getAuthSource(oauthType));
|
AuthResponse<?> response = authRequest.login(resolveAuthCallback(callback));
|
if (response.ok()) {
|
febsResponse.data(response.getData());
|
} else {
|
throw new FebsException(String.format("第三方登录失败,%s", response.getMsg()));
|
}
|
return febsResponse;
|
}
|
|
@Override
|
public FebsResponse resolveLogin(String oauthType, AuthCallback callback) throws FebsException {
|
FebsResponse febsResponse = new FebsResponse();
|
AuthRequest authRequest = factory.get(getAuthSource(oauthType));
|
AuthResponse<?> response = authRequest.login(resolveAuthCallback(callback));
|
if (response.ok()) {
|
AuthUser authUser = (AuthUser) response.getData();
|
UserConnection userConnection = userConnectionService.selectByCondition(authUser.getSource().toString(), authUser.getUuid());
|
if (userConnection == null) {
|
febsResponse.message(NOT_BIND).data(authUser);
|
} else {
|
SystemUser user = userManager.findByName(userConnection.getUserName());
|
if (user == null) {
|
throw new FebsException("系统中未找到与第三方账号对应的账户");
|
}
|
OAuth2AccessToken oAuth2AccessToken = getOauth2AccessToken(user);
|
febsResponse.message(SOCIAL_LOGIN_SUCCESS).data(oAuth2AccessToken);
|
febsResponse.put(USERNAME, user.getUsername());
|
}
|
} else {
|
throw new FebsException(String.format("第三方登录失败,%s", response.getMsg()));
|
}
|
return febsResponse;
|
}
|
|
@Override
|
public OAuth2AccessToken bindLogin(BindUser bindUser, AuthUser authUser) throws FebsException {
|
SystemUser systemUser = userManager.findByName(bindUser.getBindUsername());
|
if (systemUser == null || !passwordEncoder.matches(bindUser.getBindPassword(), systemUser.getPassword())) {
|
throw new FebsException("绑定系统账号失败,用户名或密码错误!");
|
}
|
this.createConnection(systemUser, authUser);
|
return this.getOauth2AccessToken(systemUser);
|
}
|
|
@Override
|
public OAuth2AccessToken signLogin(BindUser registUser, AuthUser authUser) throws FebsException {
|
SystemUser user = this.userManager.findByName(registUser.getBindUsername());
|
if (user != null) {
|
throw new FebsException("该用户名已存在!");
|
}
|
String encryptPassword = passwordEncoder.encode(registUser.getBindPassword());
|
SystemUser systemUser = this.userManager.registUser(registUser.getBindUsername(), encryptPassword);
|
this.createConnection(systemUser, authUser);
|
return this.getOauth2AccessToken(systemUser);
|
}
|
|
@Override
|
public void bind(BindUser bindUser, AuthUser authUser) throws FebsException {
|
String username = bindUser.getBindUsername();
|
if (isCurrentUser(username)) {
|
UserConnection userConnection = userConnectionService.selectByCondition(authUser.getSource().toString(), authUser.getUuid());
|
if (userConnection != null) {
|
throw new FebsException("绑定失败,该第三方账号已绑定" + userConnection.getUserName() + "系统账户");
|
}
|
SystemUser systemUser = new SystemUser();
|
systemUser.setUsername(username);
|
this.createConnection(systemUser, authUser);
|
} else {
|
throw new FebsException("绑定失败,您无权绑定别人的账号");
|
}
|
}
|
|
@Override
|
public void unbind(BindUser bindUser, String oauthType) throws FebsException {
|
String username = bindUser.getBindUsername();
|
if (isCurrentUser(username)) {
|
this.userConnectionService.deleteByCondition(username, oauthType);
|
} else {
|
throw new FebsException("解绑失败,您无权解绑别人的账号");
|
}
|
}
|
|
@Override
|
public List<UserConnection> findUserConnections(String username) {
|
return this.userConnectionService.selectByCondition(username);
|
}
|
|
private void createConnection(SystemUser systemUser, AuthUser authUser) {
|
UserConnection userConnection = new UserConnection();
|
userConnection.setUserName(systemUser.getUsername());
|
userConnection.setProviderName(authUser.getSource().toString());
|
userConnection.setProviderUserId(authUser.getUuid());
|
userConnection.setProviderUserName(authUser.getUsername());
|
userConnection.setImageUrl(authUser.getAvatar());
|
userConnection.setNickName(authUser.getNickname());
|
userConnection.setLocation(authUser.getLocation());
|
this.userConnectionService.createUserConnection(userConnection);
|
}
|
|
private AuthCallback resolveAuthCallback(AuthCallback callback) {
|
int stateLength = 3;
|
String state = callback.getState();
|
String[] strings = StringUtils.splitByWholeSeparatorPreserveAllTokens(state, StringConstant.DOUBLE_COLON);
|
if (strings.length == stateLength) {
|
callback.setState(strings[0] + StringConstant.DOUBLE_COLON + strings[1]);
|
}
|
return callback;
|
}
|
|
private AuthSource getAuthSource(String type) throws FebsException {
|
if (StrUtil.isNotBlank(type)) {
|
return AuthSource.valueOf(type.toUpperCase());
|
} else {
|
throw new FebsException(String.format("暂不支持%s第三方登录", type));
|
}
|
}
|
|
private boolean isCurrentUser(String username) {
|
String currentUsername = FebsUtil.getCurrentUsername();
|
return StringUtils.equalsIgnoreCase(username, currentUsername);
|
}
|
|
private OAuth2AccessToken getOauth2AccessToken(SystemUser user) throws FebsException {
|
final HttpServletRequest httpServletRequest = FebsUtil.getHttpServletRequest();
|
httpServletRequest.setAttribute(ParamsConstant.LOGIN_TYPE, SocialConstant.SOCIAL_LOGIN);
|
String socialLoginClientId = properties.getSocialLoginClientId();
|
ClientDetails clientDetails = null;
|
try {
|
clientDetails = redisClientDetailsService.loadClientByClientId(socialLoginClientId);
|
} catch (Exception e) {
|
throw new FebsException("获取第三方登录可用的Client失败");
|
}
|
if (clientDetails == null) {
|
throw new FebsException("未找到第三方登录可用的Client");
|
}
|
Map<String, String> requestParameters = new HashMap<>(5);
|
requestParameters.put(ParamsConstant.GRANT_TYPE, GrantTypeConstant.PASSWORD);
|
requestParameters.put(USERNAME, user.getUsername());
|
requestParameters.put(PASSWORD, SocialConstant.setSocialLoginPassword());
|
|
String grantTypes = String.join(StringConstant.COMMA, clientDetails.getAuthorizedGrantTypes());
|
TokenRequest tokenRequest = new TokenRequest(requestParameters, clientDetails.getClientId(), clientDetails.getScope(), grantTypes);
|
return granter.grant(GrantTypeConstant.PASSWORD, tokenRequest);
|
}
|
}
|