|
@@ -0,0 +1,211 @@
|
|
|
|
|
+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.UserConnectionService;
|
|
|
|
|
+import cc.mrbird.febs.common.entity.FebsAuthUser;
|
|
|
|
|
+import cc.mrbird.febs.common.entity.FebsResponse;
|
|
|
|
|
+import cc.mrbird.febs.common.entity.constant.GrantTypeConstant;
|
|
|
|
|
+import cc.mrbird.febs.common.entity.constant.ParamsConstant;
|
|
|
|
|
+import cc.mrbird.febs.common.entity.constant.SocialConstant;
|
|
|
|
|
+import cc.mrbird.febs.common.entity.system.SystemUser;
|
|
|
|
|
+import cc.mrbird.febs.common.exception.FebsException;
|
|
|
|
|
+import cc.mrbird.febs.common.utils.HttpContextUtil;
|
|
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
|
|
+import com.xkcoding.justauth.AuthRequestFactory;
|
|
|
|
|
+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.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.security.core.Authentication;
|
|
|
|
|
+import org.springframework.security.core.context.SecurityContextHolder;
|
|
|
|
|
+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
|
|
|
|
|
+public class 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";
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private UserManager userManager;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private AuthRequestFactory factory;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FebsAuthProperties properties;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private PasswordEncoder passwordEncoder;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private UserConnectionService userConnectionService;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private ResourceOwnerPasswordTokenGranter granter;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private RedisClientDetailsService redisClientDetailsService;
|
|
|
|
|
+
|
|
|
|
|
+ public AuthRequest renderAuth(String oauthType) throws FebsException {
|
|
|
|
|
+ return factory.get(getAuthSource(oauthType));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ 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;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ 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;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ 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);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ 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);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ 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("绑定失败,您无权绑定别人的账号");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ 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("绑定失败,您无权解绑别人的账号");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ 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) {
|
|
|
|
|
+ String state = callback.getState();
|
|
|
|
|
+ String[] strings = StringUtils.splitByWholeSeparatorPreserveAllTokens(state, "::");
|
|
|
|
|
+ if (strings.length == 3) {
|
|
|
|
|
+ callback.setState(strings[0] + "::" + 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) {
|
|
|
|
|
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
|
|
|
|
+ FebsAuthUser authUser = (FebsAuthUser) authentication.getPrincipal();
|
|
|
|
|
+ return StringUtils.equalsIgnoreCase(username, authUser.getUsername());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private OAuth2AccessToken getOAuth2AccessToken(SystemUser user) throws FebsException {
|
|
|
|
|
+ final HttpServletRequest httpServletRequest = HttpContextUtil.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.SOCIAL_LOGIN_PASSWORD);
|
|
|
|
|
+
|
|
|
|
|
+ String grantTypes = String.join(",", clientDetails.getAuthorizedGrantTypes());
|
|
|
|
|
+ TokenRequest tokenRequest = new TokenRequest(requestParameters, clientDetails.getClientId(), clientDetails.getScope(), grantTypes);
|
|
|
|
|
+ return granter.grant(GrantTypeConstant.PASSWORD, tokenRequest);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|