mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 12:18:42 +08:00 
			
		
		
		
	增加三方登陆的 redirect uri
This commit is contained in:
		@@ -117,6 +117,12 @@
 | 
			
		||||
            <artifactId>screw-core</artifactId> <!-- 实现数据库文档 -->
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <!-- TODO 后续看情况,进行调整 -->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.xkcoding.justauth</groupId>
 | 
			
		||||
            <artifactId>justauth-spring-boot-starter</artifactId>
 | 
			
		||||
            <version>1.4.0</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ public class InfFileController {
 | 
			
		||||
    @ApiOperation("上传文件")
 | 
			
		||||
    @ApiImplicitParams({
 | 
			
		||||
            @ApiImplicitParam(name = "file", value = "文件附件", required = true, dataTypeClass = MultipartFile.class),
 | 
			
		||||
            @ApiImplicitParam(name = "path", value = "文件路径", required = false, example = "yudaoyuanma.png", dataTypeClass = String.class)
 | 
			
		||||
            @ApiImplicitParam(name = "path", value = "文件路径", example = "yudaoyuanma.png", dataTypeClass = String.class)
 | 
			
		||||
    })
 | 
			
		||||
    public CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file,
 | 
			
		||||
                                           @RequestParam("path") String path) throws IOException {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,13 @@
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.controller.auth;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.net.url.UrlBuilder;
 | 
			
		||||
import cn.hutool.http.HttpUtil;
 | 
			
		||||
import cn.hutool.json.JSONUtil;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.enums.user.SysUserSocialTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthLoginRespVO;
 | 
			
		||||
@@ -18,15 +23,31 @@ import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermiss
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
 | 
			
		||||
import com.aliyuncs.CommonResponse;
 | 
			
		||||
import com.xkcoding.justauth.AuthRequestFactory;
 | 
			
		||||
import io.swagger.annotations.Api;
 | 
			
		||||
import io.swagger.annotations.ApiImplicitParam;
 | 
			
		||||
import io.swagger.annotations.ApiImplicitParams;
 | 
			
		||||
import io.swagger.annotations.ApiOperation;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
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 me.zhyd.oauth.utils.AuthStateUtils;
 | 
			
		||||
import org.apache.commons.lang.StringUtils;
 | 
			
		||||
import org.quartz.SimpleTrigger;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
import org.springframework.web.multipart.MultipartFile;
 | 
			
		||||
import org.springframework.web.util.UriBuilder;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import javax.validation.Valid;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.nio.charset.Charset;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
@@ -39,6 +60,7 @@ import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUse
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/")
 | 
			
		||||
@Validated
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class SysAuthController {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
@@ -52,6 +74,9 @@ public class SysAuthController {
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SysUserSessionService sysUserSessionService;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private AuthRequestFactory authRequestFactory;
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/login")
 | 
			
		||||
    @ApiOperation("使用账号密码登录")
 | 
			
		||||
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
 | 
			
		||||
@@ -61,17 +86,42 @@ public class SysAuthController {
 | 
			
		||||
        return success(SysAuthLoginRespVO.builder().token(token).build());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/auth2/login/{oauthType}")
 | 
			
		||||
    @ApiOperation("第三方登录")
 | 
			
		||||
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
 | 
			
		||||
    public CommonResult<SysAuthLoginRespVO> login(@PathVariable String oauthType) {
 | 
			
		||||
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
 | 
			
		||||
        //TODO NPE
 | 
			
		||||
        String token = sysUserSessionService.getSessionId(authentication.getName());
 | 
			
		||||
        // 返回结果
 | 
			
		||||
        return success(SysAuthLoginRespVO.builder().token(token).build());
 | 
			
		||||
    @GetMapping("/third-login-redirect")
 | 
			
		||||
    @ApiOperation("三方登陆的跳转")
 | 
			
		||||
    @ApiImplicitParams({
 | 
			
		||||
            @ApiImplicitParam(name = "type", value = "三方类型", required = true, dataTypeClass = Integer.class),
 | 
			
		||||
            @ApiImplicitParam(name = "redirectUri", value = "回调路径", dataTypeClass = String.class)
 | 
			
		||||
    })
 | 
			
		||||
    public CommonResult<String> login(@RequestParam("type") Integer type,
 | 
			
		||||
                                      @RequestParam("redirectUri") String redirectUri) throws IOException {
 | 
			
		||||
        // 获得对应的 AuthRequest 实现
 | 
			
		||||
        AuthRequest authRequest = authRequestFactory.get(SysUserSocialTypeEnum.valueOfType(type).getSource());
 | 
			
		||||
        // 生成跳转地址
 | 
			
		||||
        String authorizeUri = authRequest.authorize(AuthStateUtils.createState());
 | 
			
		||||
        authorizeUri = HttpUtils.replaceUrlQuery(authorizeUri, "redirect_uri", redirectUri);
 | 
			
		||||
//        authorizeUri = UrlBuilder.fromBaseUrl(authorizeUri).queryParam("redirect_uri", redirectUri).build();
 | 
			
		||||
        return CommonResult.success(authorizeUri);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/{type}/callback")
 | 
			
		||||
    public AuthResponse login(@PathVariable String type, AuthCallback callback) {
 | 
			
		||||
        AuthRequest authRequest = authRequestFactory.get(type);
 | 
			
		||||
        AuthResponse<AuthUser> response = authRequest.login(callback);
 | 
			
		||||
        log.info("【response】= {}", JSONUtil.toJsonStr(response));
 | 
			
		||||
        return response;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
//    @RequestMapping("/auth2/login/{oauthType}")
 | 
			
		||||
//    @ApiOperation("第三方登录")
 | 
			
		||||
//    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
 | 
			
		||||
//    public CommonResult<SysAuthLoginRespVO> login(@PathVariable String oauthType) {
 | 
			
		||||
//        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
 | 
			
		||||
//        //TODO NPE
 | 
			
		||||
//        String token = sysUserSessionService.getSessionId(authentication.getName());
 | 
			
		||||
//        // 返回结果
 | 
			
		||||
//        return success(SysAuthLoginRespVO.builder().token(token).build());
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/get-permission-info")
 | 
			
		||||
    @ApiOperation("获取登陆用户的权限信息")
 | 
			
		||||
    public CommonResult<SysAuthPermissionInfoRespVO> getPermissionInfo() {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +1,26 @@
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.convert.auth;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.SysUserCreateReqVO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.enums.common.SysSexEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.Auth2LoginUser;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthMenuRespVO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthPermissionInfoRespVO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdatePasswordReqVO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdateReqVO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.SysUserCreateReqVO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.enums.permission.MenuIdEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import me.zhyd.oauth.enums.AuthUserGender;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
 | 
			
		||||
import me.zhyd.oauth.model.AuthUser;
 | 
			
		||||
import org.mapstruct.*;
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.mapstruct.Mapping;
 | 
			
		||||
import org.mapstruct.Mappings;
 | 
			
		||||
import org.mapstruct.factory.Mappers;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Comparator;
 | 
			
		||||
import java.util.LinkedHashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
@Mapper(uses = SysAuthConvert.UserSexTransform.class)
 | 
			
		||||
@Mapper
 | 
			
		||||
public interface SysAuthConvert {
 | 
			
		||||
 | 
			
		||||
    SysAuthConvert INSTANCE = Mappers.getMapper(SysAuthConvert.class);
 | 
			
		||||
@@ -33,7 +28,6 @@ public interface SysAuthConvert {
 | 
			
		||||
    @Mapping(source = "updateTime", target = "updateTime", ignore = true)
 | 
			
		||||
        // 字段相同,但是含义不同,忽略
 | 
			
		||||
    LoginUser convert(SysUserDO bean);
 | 
			
		||||
    Auth2LoginUser getAuth2LoginUser(SysUserDO bean);
 | 
			
		||||
 | 
			
		||||
    default SysAuthPermissionInfoRespVO convert(SysUserDO user, List<SysRoleDO> roleList, List<SysMenuDO> menuList) {
 | 
			
		||||
        return SysAuthPermissionInfoRespVO.builder()
 | 
			
		||||
@@ -49,16 +43,6 @@ public interface SysAuthConvert {
 | 
			
		||||
 | 
			
		||||
    LoginUser convert(SysUserProfileUpdatePasswordReqVO reqVO);
 | 
			
		||||
 | 
			
		||||
    @Mappings(
 | 
			
		||||
        @Mapping(target = "sex", source = "gender")
 | 
			
		||||
    )
 | 
			
		||||
    SysUserCreateReqVO convert(AuthUser authUser);
 | 
			
		||||
 | 
			
		||||
    @Mappings(
 | 
			
		||||
        @Mapping(target = "thirdPartyUserId", source = "uuid")
 | 
			
		||||
    )
 | 
			
		||||
    Auth2LoginUser getLoginUser(AuthUser authUser);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 将菜单列表,构建成菜单树
 | 
			
		||||
     *
 | 
			
		||||
@@ -91,24 +75,4 @@ public interface SysAuthConvert {
 | 
			
		||||
        return CollectionUtils.filterList(treeNodeMap.values(), node -> MenuIdEnum.ROOT.getId().equals(node.getParentId()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class UserSexTransform {
 | 
			
		||||
 | 
			
		||||
        public int toInt (AuthUserGender gender){
 | 
			
		||||
            switch (gender) {
 | 
			
		||||
                case MALE:
 | 
			
		||||
                    return SysSexEnum.MALE.getSex();
 | 
			
		||||
                case  FEMALE:
 | 
			
		||||
                    return  SysSexEnum.FEMALE.getSex();
 | 
			
		||||
                default:
 | 
			
		||||
                    return SysSexEnum.UNKNOWN.getSex();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public AuthUserGender strToBoolean(int sex){
 | 
			
		||||
            if(sex == SysSexEnum.UNKNOWN.getSex()) {
 | 
			
		||||
                return AuthUserGender.UNKNOWN;
 | 
			
		||||
            }
 | 
			
		||||
            return AuthUserGender.getRealGender(String.valueOf(sex));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.convert.auth.config;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.convert.auth.handler.DefaultSignUpUrlAuthenticationSuccessHandler;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.handler.AbstractSignUpUrlAuthenticationSuccessHandler;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author weir
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
public class AuthConfig {
 | 
			
		||||
    @Bean
 | 
			
		||||
    public AbstractSignUpUrlAuthenticationSuccessHandler authenticationSuccessHandler() {
 | 
			
		||||
        AbstractSignUpUrlAuthenticationSuccessHandler successHandler = new DefaultSignUpUrlAuthenticationSuccessHandler();
 | 
			
		||||
        successHandler.setDefaultTargetUrl("/api/callback");
 | 
			
		||||
        return successHandler;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,113 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * Copyright (c) 2020-2029 YongWu zheng (dcenter.top and gitee.com/pcore and github.com/ZeroOrInfinity)
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.convert.auth.handler;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthLoginRespVO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.Auth2LoginUser;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.handler.AbstractSignUpUrlAuthenticationSuccessHandler;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import org.springframework.security.web.DefaultRedirectStrategy;
 | 
			
		||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
 | 
			
		||||
import org.springframework.security.web.savedrequest.RequestCache;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import javax.servlet.ServletException;
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUserAgent;
 | 
			
		||||
import static java.util.Collections.singleton;
 | 
			
		||||
import static top.dcenter.ums.security.core.oauth.util.MvcUtil.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author weir
 | 
			
		||||
 */
 | 
			
		||||
public class DefaultSignUpUrlAuthenticationSuccessHandler extends AbstractSignUpUrlAuthenticationSuccessHandler {
 | 
			
		||||
    private RequestCache requestCache = new HttpSessionRequestCache();
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private SysUserSessionService userSessionService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SysPermissionService permissionService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
 | 
			
		||||
        final Object principal = authentication.getPrincipal();
 | 
			
		||||
        String token = userSessionService.createUserSession(defaultHandleUserRoles((LoginUser) principal), getClientIP(), getUserAgent());
 | 
			
		||||
        if(StringUtils.isNotBlank(token)) {
 | 
			
		||||
            SecurityContextHolder.getContext().setAuthentication(authentication);
 | 
			
		||||
        }
 | 
			
		||||
        if (principal instanceof Auth2LoginUser) {
 | 
			
		||||
            new DefaultRedirectStrategy().sendRedirect(request, response, getUrl() + token);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (isAjaxOrJson(request)) {
 | 
			
		||||
            responseWithJson(response, HttpStatus.OK.value(), toJsonString(success(SysAuthLoginRespVO.builder().token(token).build())));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            requestCache.saveRequest(request, response);
 | 
			
		||||
            super.setRequestCache(requestCache);
 | 
			
		||||
            super.onAuthenticationSuccess(request, response, authentication);
 | 
			
		||||
        } catch (ServletException e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String getUrl() {
 | 
			
		||||
//        return "http://localhost/oauthLogin/gitee?token=";
 | 
			
		||||
        return "http://127.0.0.1:1024/oauthLogin/gitee?token=";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 默认处理方式处理用户角色列表;建议角色权限前置到 UserDetails
 | 
			
		||||
     *
 | 
			
		||||
     * @param loginUser 用户
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    private LoginUser defaultHandleUserRoles(LoginUser loginUser) {
 | 
			
		||||
        Set<Long> roleIds = loginUser.getRoleIds();
 | 
			
		||||
        if (roleIds == null || roleIds.isEmpty()) {
 | 
			
		||||
            Set<Long> userRoleIds = permissionService.getUserRoleIds(loginUser.getId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
 | 
			
		||||
            loginUser.setRoleIds(userRoleIds);
 | 
			
		||||
        }
 | 
			
		||||
        return loginUser;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setRequestCache(RequestCache requestCache) {
 | 
			
		||||
        this.requestCache = requestCache;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableName;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import me.zhyd.oauth.model.AuthUser;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author weir
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@TableName("user_connection")
 | 
			
		||||
public class SocialUserDO extends AuthUser {
 | 
			
		||||
}
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableId;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableName;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 系统用户和第三方用户关联表
 | 
			
		||||
 * @author weir
 | 
			
		||||
 */
 | 
			
		||||
@TableName("sys_user_social")
 | 
			
		||||
@Data
 | 
			
		||||
public class SysUserSocialDO extends BaseDO {
 | 
			
		||||
    /**
 | 
			
		||||
     * 自增主键
 | 
			
		||||
     */
 | 
			
		||||
    @TableId
 | 
			
		||||
    private Long id;
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户 ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long userId;
 | 
			
		||||
    /**
 | 
			
		||||
     * 角色 ID
 | 
			
		||||
     */
 | 
			
		||||
    private String socialUserId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,75 @@
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.enums.user.SysUserSocialTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableId;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableName;
 | 
			
		||||
import lombok.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 三方登陆信息
 | 
			
		||||
 * 通过 {@link SysUserSocialDO#getUserId()} 关联到对应的 {@link SysUserDO}
 | 
			
		||||
 *
 | 
			
		||||
 * @author weir
 | 
			
		||||
 */
 | 
			
		||||
@TableName(value = "sys_user_social", autoResultMap = true)
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@Builder
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class SysUserSocialDO extends BaseDO {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 自增主键
 | 
			
		||||
     */
 | 
			
		||||
    @TableId
 | 
			
		||||
    private Long id;
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户编号
 | 
			
		||||
     */
 | 
			
		||||
    private Long userId;
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户类型
 | 
			
		||||
     *
 | 
			
		||||
     * 枚举 {@link UserTypeEnum}
 | 
			
		||||
     */
 | 
			
		||||
    private Integer userType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 三方平台的类型
 | 
			
		||||
     */
 | 
			
		||||
    private SysUserSocialTypeEnum type;
 | 
			
		||||
    /**
 | 
			
		||||
     * 三方 openid
 | 
			
		||||
     */
 | 
			
		||||
    private String openid;
 | 
			
		||||
    /**
 | 
			
		||||
     * 三方 token
 | 
			
		||||
     */
 | 
			
		||||
    private String token;
 | 
			
		||||
    /**
 | 
			
		||||
     * 三方的全局编号
 | 
			
		||||
     *
 | 
			
		||||
     * 例如说,微信平台的 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html
 | 
			
		||||
     * 如果没有 unionId 的平台,直接使用 openid 作为该字段的值
 | 
			
		||||
     */
 | 
			
		||||
    private String unionId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户昵称
 | 
			
		||||
     */
 | 
			
		||||
    private String nickname;
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户头像
 | 
			
		||||
     */
 | 
			
		||||
    private String avatar;
 | 
			
		||||
    /**
 | 
			
		||||
     * 原始数据,一般是 JSON 格式
 | 
			
		||||
     */
 | 
			
		||||
    private String info;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysUserSocialDO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserSocialDO;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
			
		||||
import org.apache.ibatis.annotations.Mapper;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysUserSocialDO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserSocialDO;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
			
		||||
import org.apache.ibatis.annotations.Mapper;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.enums.user;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.ArrayUtil;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.enums.errorcode.SysErrorCodeTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
 | 
			
		||||
import jodd.util.ArraysUtil;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用户的三方平台的类型枚举
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Getter
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public enum SysUserSocialTypeEnum implements IntArrayValuable {
 | 
			
		||||
 | 
			
		||||
    GITEE(10, "GITEE"), // https://gitee.com/api/v5/oauth_doc#/
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysUserSocialTypeEnum::getType).toArray();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 类型
 | 
			
		||||
     */
 | 
			
		||||
    private final Integer type;
 | 
			
		||||
    /**
 | 
			
		||||
     * 类型的标识
 | 
			
		||||
     */
 | 
			
		||||
    private final String source;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int[] array() {
 | 
			
		||||
        return ARRAYS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static SysUserSocialTypeEnum valueOfType(Integer type) {
 | 
			
		||||
        return ArrayUtil.firstMatch(o -> o.getType().equals(type), values());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,237 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * Copyright (c) 2020-2029 YongWu zheng (dcenter.top and gitee.com/pcore and github.com/ZeroOrInfinity)
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package cn.iocoder.yudao.adminserver.modules.system.service.auth.impl;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.SysUserCreateReqVO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.convert.auth.SysAuthConvert;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.Auth2LoginUser;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
 | 
			
		||||
import com.google.common.collect.Sets;
 | 
			
		||||
import me.zhyd.oauth.model.AuthUser;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.lang.NonNull;
 | 
			
		||||
import org.springframework.security.core.authority.AuthorityUtils;
 | 
			
		||||
import org.springframework.security.core.userdetails.User;
 | 
			
		||||
import org.springframework.security.core.userdetails.UserCache;
 | 
			
		||||
import org.springframework.security.core.userdetails.UserDetails;
 | 
			
		||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
 | 
			
		||||
import org.springframework.security.crypto.password.PasswordEncoder;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.web.context.request.RequestAttributes;
 | 
			
		||||
import org.springframework.web.context.request.RequestContextHolder;
 | 
			
		||||
import top.dcenter.ums.security.core.oauth.enums.ErrorCodeEnum;
 | 
			
		||||
import top.dcenter.ums.security.core.oauth.exception.RegisterUserFailureException;
 | 
			
		||||
import top.dcenter.ums.security.core.oauth.exception.UserNotExistException;
 | 
			
		||||
import top.dcenter.ums.security.core.oauth.service.UmsUserDetailsService;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  用户密码与手机短信登录与注册服务:<br><br>
 | 
			
		||||
 *  1. 用于第三方登录与手机短信登录逻辑。<br><br>
 | 
			
		||||
 *  2. 用于用户密码登录逻辑。<br><br>
 | 
			
		||||
 *  3. 用户注册逻辑。<br><br>
 | 
			
		||||
 * @author YongWu zheng
 | 
			
		||||
 * @version V1.0  Created by 2020/9/20 11:06
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
public class UserDetailsServiceImpl implements UmsUserDetailsService {
 | 
			
		||||
 | 
			
		||||
    private final Logger log = LoggerFactory.getLogger(this.getClass());
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
 | 
			
		||||
    @Autowired(required = false)
 | 
			
		||||
    private UserCache userCache;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SysUserService userService;
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * 用于密码加解密
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private PasswordEncoder passwordEncoder;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private SysPermissionService permissionService;
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("AlibabaUndefineMagicConstant")
 | 
			
		||||
    @Override
 | 
			
		||||
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            // 从缓存中查询用户信息:
 | 
			
		||||
            // 从缓存中查询用户信息
 | 
			
		||||
            if (this.userCache != null)
 | 
			
		||||
            {
 | 
			
		||||
                UserDetails userDetails = this.userCache.getUserFromCache(username);
 | 
			
		||||
                if (userDetails != null)
 | 
			
		||||
                {
 | 
			
		||||
                    return userDetails;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // 根据用户名获取用户信息
 | 
			
		||||
            // 获取 username 对应的 SysUserDO
 | 
			
		||||
            SysUserDO user = userService.getUserByUsername(username);
 | 
			
		||||
            if (user == null) {
 | 
			
		||||
                throw new UsernameNotFoundException(username);
 | 
			
		||||
            }
 | 
			
		||||
            // 创建 LoginUser 对象
 | 
			
		||||
            Auth2LoginUser loginUser = SysAuthConvert.INSTANCE.getAuth2LoginUser(user);
 | 
			
		||||
            //TODO 登录日志等可以和用户名密码等兼容处理
 | 
			
		||||
           return loginUser;
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception e)
 | 
			
		||||
        {
 | 
			
		||||
            String msg = String.format("第三方登录 ======>: 登录用户名:%s, 登录失败: %s", username, e.getMessage());
 | 
			
		||||
            log.error(msg);
 | 
			
		||||
            throw new UserNotExistException(ErrorCodeEnum.QUERY_USER_INFO_ERROR, e, username);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public UserDetails registerUser(@NonNull AuthUser authUser, @NonNull String username,
 | 
			
		||||
                                    @NonNull String defaultAuthority, String decodeState) throws RegisterUserFailureException {
 | 
			
		||||
 | 
			
		||||
        // 这里的 decodeState 可以根据自己实现的 top.dcenter.ums.security.core.oauth.service.Auth2StateCoder 接口的逻辑来传递必要的参数.
 | 
			
		||||
        // 比如: 第三方登录成功后的跳转地址
 | 
			
		||||
        final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
 | 
			
		||||
        // 假设 decodeState 就是 redirectUrl, 我们直接把 redirectUrl 设置到 request 上
 | 
			
		||||
        // 后续经过成功处理器时直接从 requestAttributes.getAttribute("redirectUrl", RequestAttributes.SCOPE_REQUEST) 获取并跳转
 | 
			
		||||
        if (requestAttributes != null) {
 | 
			
		||||
            requestAttributes.setAttribute("redirectUrl", decodeState, RequestAttributes.SCOPE_REQUEST);
 | 
			
		||||
        }
 | 
			
		||||
        //返回用户
 | 
			
		||||
        LoginUser loginUser = doRegistUser(authUser);
 | 
			
		||||
 | 
			
		||||
        log.info("第三方用户注册 ======>: 用户名:{}, 注册成功", username);
 | 
			
		||||
 | 
			
		||||
        // 把用户信息存入缓存
 | 
			
		||||
        if (userCache != null)
 | 
			
		||||
        {
 | 
			
		||||
            userCache.putUserInCache(loginUser);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return loginUser;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private LoginUser doRegistUser(AuthUser authUser) {
 | 
			
		||||
        SysUserCreateReqVO reqVO = SysAuthConvert.INSTANCE.convert(authUser);
 | 
			
		||||
        if (StringUtils.isEmpty(reqVO.getPassword())) {
 | 
			
		||||
            reqVO.setPassword(getDefaultPassword());
 | 
			
		||||
        }
 | 
			
		||||
        //添加用户
 | 
			
		||||
        Long sysUserId = userService.createUser(reqVO);
 | 
			
		||||
        //关联第三方用户
 | 
			
		||||
        Long userId = userService.bindSocialUSer(sysUserId, authUser.getUuid());
 | 
			
		||||
        //赋予默认角色权限;三方登录默认部分
 | 
			
		||||
        permissionService.assignUserRole(userId, getDefaultRoles());
 | 
			
		||||
        LoginUser loginUser = SysAuthConvert.INSTANCE.getLoginUser(authUser);
 | 
			
		||||
        loginUser.setRoleIds(getDefaultRoles());
 | 
			
		||||
        loginUser.setPassword(getDefaultPassword());
 | 
			
		||||
        loginUser.setId(sysUserId);
 | 
			
		||||
        return loginUser;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String getDefaultPassword() {
 | 
			
		||||
        return "123456";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected Set<Long> getDefaultRoles() {
 | 
			
		||||
        return Sets.newHashSet(1L);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    public UserDetails registerUser(@NonNull String mobile, Map<String, String> otherParamMap) throws RegisterUserFailureException {
 | 
			
		||||
 | 
			
		||||
        // 用户信息持久化逻辑。。。
 | 
			
		||||
        // ...
 | 
			
		||||
 | 
			
		||||
        log.info("Demo ======>: 手机短信登录用户 {}:注册成功", mobile);
 | 
			
		||||
 | 
			
		||||
        User user = new User(mobile,
 | 
			
		||||
                             passwordEncoder.encode("admin"),
 | 
			
		||||
                             true,
 | 
			
		||||
                             true,
 | 
			
		||||
                             true,
 | 
			
		||||
                             true,
 | 
			
		||||
                             AuthorityUtils.commaSeparatedStringToAuthorityList("admin, ROLE_USER")
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // 把用户信息存入缓存
 | 
			
		||||
        if (userCache != null)
 | 
			
		||||
        {
 | 
			
		||||
            userCache.putUserInCache(user);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return user;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * {@link #existedByUsernames(String...)} usernames 生成规则.
 | 
			
		||||
     * 如需自定义重新实现此逻辑
 | 
			
		||||
     * @param authUser     第三方用户信息
 | 
			
		||||
     * @return  返回一个 username 数组
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] generateUsernames(AuthUser authUser) {
 | 
			
		||||
        return new String[]{
 | 
			
		||||
                authUser.getUsername(),
 | 
			
		||||
                // providerId = authUser.getSource()
 | 
			
		||||
                authUser.getUsername() + "_" + authUser.getSource(),
 | 
			
		||||
                // providerUserId = authUser.getUuid()
 | 
			
		||||
                authUser.getUsername() + "_" + authUser.getSource() + "_" + authUser.getUuid()
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public UserDetails loadUserByUserId(String userId) throws UsernameNotFoundException {
 | 
			
		||||
        UserDetails userDetails = loadUserByUsername(userId);
 | 
			
		||||
        User.withUserDetails(userDetails);
 | 
			
		||||
        return userDetails;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<Boolean> existedByUsernames(String... usernames) throws UsernameNotFoundException {
 | 
			
		||||
        // ... 在本地账户上查询 userIds 是否已被使用
 | 
			
		||||
        List<Boolean> list = new ArrayList<>();
 | 
			
		||||
        for (String username : usernames) {
 | 
			
		||||
            SysUserDO userDO = userService.getUserByUsername(username);
 | 
			
		||||
            list.add(userDO != null);
 | 
			
		||||
        }
 | 
			
		||||
        return list;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.hutool.core.io.IoUtil;
 | 
			
		||||
import cn.hutool.core.util.IdUtil;
 | 
			
		||||
import cn.hutool.core.util.StrUtil;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysUserSocialDO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserSocialDO;
 | 
			
		||||
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social.SysUserSocialMapper;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
 | 
			
		||||
@@ -82,7 +82,7 @@ public class SysUserServiceImpl implements SysUserService {
 | 
			
		||||
    public Long bindSocialUSer(Long sysUserId, String socialUSerId) {
 | 
			
		||||
        SysUserSocialDO userSocialDO = new SysUserSocialDO();
 | 
			
		||||
        userSocialDO.setUserId(sysUserId);
 | 
			
		||||
        userSocialDO.setSocialUserId(socialUSerId);
 | 
			
		||||
//        userSocialDO.setSocialUserId(socialUSerId);
 | 
			
		||||
        userSocialMapper.insert(userSocialDO);
 | 
			
		||||
        return userSocialDO.getUserId();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -168,220 +168,13 @@ yudao:
 | 
			
		||||
      - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
 | 
			
		||||
  demo: false # 关闭演示模式
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# ums core
 | 
			
		||||
ums:
 | 
			
		||||
  one-click-login:
 | 
			
		||||
    # 一键登录是否开启, 默认 false
 | 
			
		||||
    enable: true
 | 
			
		||||
    # 一键登录请求处理 url, 默认 /authentication/one-click
 | 
			
		||||
    login-processing-url: /authentication/one-click
 | 
			
		||||
    # token 参数名称, 默认: accessToken
 | 
			
		||||
    token-param-name: accessToken
 | 
			
		||||
    # 其他请求参数名称列表(包括请求头名称), 此参数会传递到 OneClickLoginService.callback(String, Map)
 | 
			
		||||
    # 与 UserDetailsRegisterService.registerUser(String, Map); 默认为: 空
 | 
			
		||||
    other-param-names:
 | 
			
		||||
      - imei
 | 
			
		||||
  # ================ 第三方授权登录相关配置 ================
 | 
			
		||||
  oauth:
 | 
			
		||||
    # 第三方授权登录后如未注册用户是否支持自动注册功能, 默认: true
 | 
			
		||||
    auto-sign-up: true
 | 
			
		||||
    # 第三方授权登录后如未注册用户不支持自动注册功能, 则跳转到此 url 进行注册逻辑, 此 url 必须开发者自己实现; 默认: /signUp.html;
 | 
			
		||||
    # 注意: 当 autoSignUp = false 时, 此属性才生效.
 | 
			
		||||
    # 例如: 1. 设置值 "/signUp", 则跳转指定到 "/signUp" 进行注册.
 | 
			
		||||
    # 2. 想返回自定义 json 数据到前端, 这里要设置 null , 在 Auth2LoginAuthenticationFilter 设置的 AuthenticationSuccessHandler
 | 
			
		||||
    # 上处理返回 json; 判断是否为临时用户的条件是: Authentication.getPrincipal() 是否为 TemporaryUser 类型.
 | 
			
		||||
    sign-up-url: null
 | 
			
		||||
    # 用于第三方授权登录时, 未开启自动注册且用户是第一次授权登录的临时用户密码, 默认为: "". 注意: 生产环境更换密码
 | 
			
		||||
    temporary-user-password: ""
 | 
			
		||||
    # 用于第三方授权登录时, 未开启自动注册且用户是第一次授权登录的临时用户的默认权限, 多个权限用逗号分开, 默认为: "ROLE_TEMPORARY_USER"
 | 
			
		||||
    temporary-user-authorities: ROLE_TEMPORARY_USER
 | 
			
		||||
    # 抑制反射警告, 支持 JDK11, 默认: false , 在确认 WARNING: An illegal reflective access operation has occurred 安全后, 可以打开此设置, 可以抑制反射警告.
 | 
			
		||||
    suppress-reflect-warning: true
 | 
			
		||||
    # 第三方服务商: providerId, 支持所有 JustAuth 支持的第三方授权登录, 目前有 32 家第三方授权登录
 | 
			
		||||
    github:
 | 
			
		||||
      # 根据是否有设置 clientId 来动态加载相应 JustAuth 的 AuthXxxRequest
 | 
			
		||||
      client-id: 4d4ee00e82f669f2ea8d
 | 
			
		||||
      client-secret: 4050be113a83556b63bd991d606fded437b05235
 | 
			
		||||
      scopes:
 | 
			
		||||
    #        - 'repo:status'
 | 
			
		||||
    #        - 'public_repo'
 | 
			
		||||
    #        - 'repo:invite'
 | 
			
		||||
    #        - 'user:follow'
 | 
			
		||||
    gitee:
 | 
			
		||||
      client-id: eb5e3298cc10ead57cd40f9f36e7154ab2ea54dcb519684d7e10ca3fec5b1c1a
 | 
			
		||||
      client-secret: 495b5542dc007e2d46d316c527bd05dac586f2ec31b96c551e164387b5edb1cb
 | 
			
		||||
      scopes:
 | 
			
		||||
        - user_info
 | 
			
		||||
#    # 自定义 OAuth2 Login
 | 
			
		||||
#    customize:
 | 
			
		||||
#      client-id: c971cf1634460e18310a5d7cb0f55d7d143a72015b2f29aee6a0e8911efac7eb
 | 
			
		||||
#      client-secret: 309c9521721e3eb385a99a6bde2755f3107c7e15f3b8e0527c9f3ea4d1ce33bb
 | 
			
		||||
#      # 自定义第三方授权登录时, 当 Auth2Properties#customize 时有效, 此字段必须以驼峰方式命名.
 | 
			
		||||
#      # 比如此字段的值为 umsCustomize, 那么 /auth2/authorization/customize 会替换为 /auth2/authorization/umsCustomize
 | 
			
		||||
#      customize-provider-id: giteeCustomize
 | 
			
		||||
#      # 自定义第三方授权登录, 当 Auth2Properties#customize 时有效, 设置第三方是否在国外, 默认: false.
 | 
			
		||||
#      # 如果为 false 时, 设置 {@link HttpConfig} 的超时时间为 ums.oauth.proxy.timeout 的值.
 | 
			
		||||
#      # 如果为 true 时, 设置 {@link HttpConfig} 的超时时间为 ums.oauth.proxy.foreignTimeout 的值.
 | 
			
		||||
#      customize-is-foreign: false
 | 
			
		||||
    # 第三方登录授权登录 url 前缀, 不包含 ServletContextPath,默认为 /auth2/authorization.
 | 
			
		||||
    auth-login-url-prefix: /api/auth2/authorization
 | 
			
		||||
    # 第三方登录回调处理 url 前缀 ,也就是 RedirectUrl 的前缀, 不包含 ServletContextPath,默认为 /auth2/login.
 | 
			
		||||
    redirect-url-prefix: /api/auth2/login
 | 
			
		||||
    # 第三方登录回调的域名, 例如:http://localhost:9090 默认为 "http://127.0.0.1",
 | 
			
		||||
    # redirectUrl 直接由 {domain}/{servletContextPath}/{redirectUrlPrefix}/{providerId}(ums.oauth.[qq/gitee/weibo])组成
 | 
			
		||||
    domain: http://localhost:48080
 | 
			
		||||
    # 第三方授权登录成功后的默认权限, 多个权限用逗号分开, 默认为: "ROLE_USER"
 | 
			
		||||
    default-authorities: ROLE_USER
 | 
			
		||||
    # 是否支持内置的第三方登录用户表(user_connection) 和 auth_token 表. 默认: true.
 | 
			
		||||
    # 注意: 如果为 false, 则必须重新实现 ConnectionService 接口.
 | 
			
		||||
    enable-user-connection-and-auth-token-table: true
 | 
			
		||||
    # 是否支持内置的第三方登录 token 表(auth_token). 默认: true.
 | 
			
		||||
    enable-auth-token-table: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # ================ start: 定时刷新 access token 定时任务相关配置 ================
 | 
			
		||||
 | 
			
		||||
    # 是否支持定时刷新 AccessToken 定时任务. 默认: false.
 | 
			
		||||
    # 支持分布式(分布式 IOC 容器中必须有 RedisConnectionFactory, 也就是说, 是否分布式执行依据 IOC 容器中是否有 RedisConnectionFactory)
 | 
			
		||||
    enableRefreshTokenJob: false
 | 
			
		||||
    # A cron-like expression. 0 * 2 * * ? 分别对应: second/minute/hour/day of month/month/day of week,
 | 
			
		||||
    # 默认为: "0 * 2 * * ?", 凌晨 2 点启动定时任务, 支持分布式(分布式 IOC 容器中必须有 {@link RedisConnectionFactory},
 | 
			
		||||
    # 也就是说, 是否分布式执行依据 IOC 容器中是否有 {@link RedisConnectionFactory})
 | 
			
		||||
    refresh-token-job-cron: 0 0/5 * * * ?
 | 
			
		||||
    # 定时刷新 accessToken 任务时, 批处理数据库的记录数. 注意: 分布式应用时, 此配置不同服务器配置必须是一样的. batchCount 大小需要根据实际生产环境进行优化
 | 
			
		||||
    batch-count: 1000
 | 
			
		||||
    # accessToken 的剩余有效期内进行刷新 accessToken, 默认: 24, 单位: 小时. 注意: 需要根据实际生产环境进行优化
 | 
			
		||||
    remaining-expire-in: 24
 | 
			
		||||
 | 
			
		||||
    # ================ start: 定时刷新 access token 定时任务相关配置 ================
 | 
			
		||||
 | 
			
		||||
    # JustAuth 内部参数设置
 | 
			
		||||
    just-auth:
 | 
			
		||||
      # 忽略校验 state 参数,默认不开启。当 ignoreCheckState 为 true 时, me.zhyd.oauth.request.AuthDefaultRequest.login(AuthCallback) 将不会校验 state 的合法性。
 | 
			
		||||
      # 使用场景:当且仅当使用自实现 state 校验逻辑时开启
 | 
			
		||||
      # 以下场景使用方案仅作参考:
 | 
			
		||||
      # 1. 授权、登录为同端,并且全部使用 JustAuth 实现时,该值建议设为 false;
 | 
			
		||||
      # 2. 授权和登录为不同端实现时,比如前端页面拼装 authorizeUrl,并且前端自行对state进行校验,后端只负责使用code获取用户信息时,该值建议设为 true;
 | 
			
		||||
      # 如非特殊需要,不建议开启这个配置
 | 
			
		||||
      # 该方案主要为了解决以下类似场景的问题:Since: 1.15.6, See Also: https://github.com/justauth/JustAuth/issues/83
 | 
			
		||||
      ignoreCheckState: false
 | 
			
		||||
      # 默认 state 缓存过期时间:3分钟(PT180S) 鉴于授权过程中,根据个人的操作习惯,或者授权平台的不同(google等),每个授权流程的耗时也有差异,
 | 
			
		||||
      # 不过单个授权流程一般不会太长 本缓存工具默认的过期时间设置为3分钟,即程序默认认为3分钟内的授权有效,超过3分钟则默认失效,失效后删除
 | 
			
		||||
      # 注意: 这是为了测试打断点时用的, 生产环境自己设置为合适数组或默认
 | 
			
		||||
      timeout: PT1800S
 | 
			
		||||
      # JustAuth state 缓存类型, 默认 session
 | 
			
		||||
      cacheType: session
 | 
			
		||||
      # JustAuth state 缓存 key 前缀
 | 
			
		||||
      cacheKeyPrefix: 'JUST_AUTH:'
 | 
			
		||||
 | 
			
		||||
    # 用于 JustAuth 的代理(HttpClient)设置
 | 
			
		||||
    proxy:
 | 
			
		||||
      # 是否支持代理, 默认为: false.
 | 
			
		||||
      enable: false
 | 
			
		||||
      # 针对国外服务可以单独设置代理类型, 默认 Proxy.Type.HTTP, enable = true 时生效.
 | 
			
		||||
      proxy: HTTP
 | 
			
		||||
      # 代理 host, enable = true 时生效.
 | 
			
		||||
      hostname:
 | 
			
		||||
      # 代理端口, enable = true 时生效.
 | 
			
		||||
      port:
 | 
			
		||||
      # 用于国内代理(HttpClient)超时, 默认 PT3S
 | 
			
		||||
      timeout: PT3S
 | 
			
		||||
      # 用于国外网站代理(HttpClient)超时, 默认 PT15S
 | 
			
		||||
      foreign-timeout: PT150S
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  # =============== start: 第三方登录时用的数据库表 user_connection 与 auth_token 添加 redis cache ===============
 | 
			
		||||
justauth:
 | 
			
		||||
  enabled: true
 | 
			
		||||
  type:
 | 
			
		||||
    GITEE:
 | 
			
		||||
      client-id: 6bb0b37a8a017e5e2dc4c34ca4756dcf80e8e392585e7035d3ede7a6db50426e
 | 
			
		||||
      client-secret: f117b9de5e9267bcd48db83d4cb078ea8cf9a5d17cda83481e3d9090df3fa01d
 | 
			
		||||
      ignore-check-redirect-uri: true
 | 
			
		||||
#      redirect-uri: http://127.0.0.1:48080/api/gitee/callback
 | 
			
		||||
  cache:
 | 
			
		||||
    # redisCacheManager 设置, 默认实现: 对查询结果 null 值进行缓存, 添加时更新缓存 null 值.
 | 
			
		||||
    redis:
 | 
			
		||||
      # 是否开启缓存, 默认 false
 | 
			
		||||
      open: false
 | 
			
		||||
      # 是否使用 spring IOC 容器中的 RedisConnectionFactory, 默认: false
 | 
			
		||||
      # 如果使用 spring IOC 容器中的 RedisConnectionFactory,则要注意 cache.database-index 要与 spring.redis.database 一样。
 | 
			
		||||
      use-ioc-redis-connection-factory: true
 | 
			
		||||
      cache:
 | 
			
		||||
        # redis cache 存放的 database index, 默认: 0
 | 
			
		||||
        database-index: 1
 | 
			
		||||
        # 设置缓存管理器管理的缓存的默认过期时间, 默认: 200s
 | 
			
		||||
        default-expire-time: PT200S
 | 
			
		||||
        # cache ttl 。使用 0 声明一个永久的缓存。 默认: 180, 单位: 秒<br>
 | 
			
		||||
        # 取缓存时间的 20% 作为动态的随机变量上下浮动, 防止同时缓存失效而缓存击穿
 | 
			
		||||
        entry-ttl: PT180S
 | 
			
		||||
        # Names of the default caches to consider for caching operations defined in the annotated class.
 | 
			
		||||
        # 此设置不对 user_connection 与 auth_token 使用的缓存名称(UCC/UCHC/UCHACC)产生影响.
 | 
			
		||||
        cache-names:
 | 
			
		||||
          - cacheName
 | 
			
		||||
  # =============== end: 第三方登录时用的数据库表 user_connection 与 auth_token 添加 redis cache ===============
 | 
			
		||||
 | 
			
		||||
  # =============== start: 线程池配置 ===============
 | 
			
		||||
  executor:
 | 
			
		||||
    # 启动第三方授权登录用户的 accessToken 的定时任务时的 Executor 属性, 注意: 需要根据实际生产环境进行优化
 | 
			
		||||
    job-task-scheduled-executor:
 | 
			
		||||
      # 线程池中空闲时保留的线程数, 默认: 0
 | 
			
		||||
      core-pool-size: 0
 | 
			
		||||
      # keep alive time, 默认: 10
 | 
			
		||||
      keep-alive-time: 0
 | 
			
		||||
      # keepAliveTime 时间单位, 默认: 毫秒
 | 
			
		||||
      time-unit: milliseconds
 | 
			
		||||
      # 线程池名称, 默认: accessTokenJob
 | 
			
		||||
      pool-name: accessTokenJob
 | 
			
		||||
      # 拒绝策略, 默认: ABORT
 | 
			
		||||
      rejected-execution-handler-policy: abort
 | 
			
		||||
      # 线程池关闭过程的超时时间, 默认: PT10S
 | 
			
		||||
      executor-shutdown-timeout: PT10S
 | 
			
		||||
    # 更新第三方授权登录用户的 accessToken 的执行逻辑, 向本地数据库 auth_token 表获取过期或在一定时间内过期的 token 记录,
 | 
			
		||||
    # 用 refreshToken 向第三方服务商更新 accessToken 信息的 Executor 属性,
 | 
			
		||||
    # 注意: 定时刷新 accessToken 的执行逻辑是多线程的, 需要根据实际生产环境进行优化
 | 
			
		||||
    refresh-token:
 | 
			
		||||
      # 程池中空闲时保留的线程数, 默认: 0
 | 
			
		||||
      core-pool-size: 0
 | 
			
		||||
      # 最大线程数, 默认: 本机核心数
 | 
			
		||||
      maximum-pool-size: 8
 | 
			
		||||
      # keep alive time, 默认: 5
 | 
			
		||||
      keep-alive-time: 5
 | 
			
		||||
      # keepAliveTime 时间单位, 默认: 秒
 | 
			
		||||
      time-unit: seconds
 | 
			
		||||
      # blocking queue capacity, 默认: maximumPoolSize * 2
 | 
			
		||||
      blocking-queue-capacity: 16
 | 
			
		||||
      # 线程池名称, 默认: refreshToken
 | 
			
		||||
      pool-name: refreshToken
 | 
			
		||||
      # 拒绝策略, 默认: CALLER_RUNS 注意: 一般情况下不要更改默认设置, 没有实现 RefreshToken 逻辑被拒绝执行后的处理逻辑, 除非自己实现RefreshTokenJob.refreshTokenJob() 对 RefreshToken 逻辑被拒绝执行后的处理逻辑.
 | 
			
		||||
      rejected-execution-handler-policy: caller_runs
 | 
			
		||||
      # 线程池关闭过程的超时时间, 默认: 10 秒
 | 
			
		||||
      executor-shutdown-timeout: PT10S
 | 
			
		||||
    # 第三方授权登录时, 异步更新用户的第三方授权用户信息与 token 信息的 Executor 属性,
 | 
			
		||||
    # 注意: 第三方授权登录时是异步更新第三方用户信息与 token 信息到本地数据库时使用此配置, 需要根据实际生产环境进行优化
 | 
			
		||||
    user-connection-update:
 | 
			
		||||
      # 程池中空闲时保留的线程数, 默认: 5
 | 
			
		||||
      core-pool-size: 5
 | 
			
		||||
      # 最大线程数, 默认: 本机核心数
 | 
			
		||||
      maximum-pool-size: 8
 | 
			
		||||
      # keep alive time, 默认: 10
 | 
			
		||||
      keep-alive-time:
 | 
			
		||||
      # keepAliveTime 时间单位, 默认: 秒
 | 
			
		||||
      time-unit: seconds
 | 
			
		||||
      # blocking queue capacity, 默认: maximumPoolSize * 2
 | 
			
		||||
      blocking-queue-capacity: 16
 | 
			
		||||
      # 线程池名称, 默认: updateConnection
 | 
			
		||||
      pool-name: updateConnection
 | 
			
		||||
      # 拒绝策略, 默认: CALLER_RUNS 注意: 一般情况下不要更改默认设置, 除非自己实现Auth2LoginAuthenticationProvider更新逻辑;
 | 
			
		||||
      # 改成 ABORT 也支持, 默认实现 Auth2LoginAuthenticationProvider 是异步更新被拒绝执行后, 会执行同步更新.
 | 
			
		||||
      rejected-execution-handler-policy: caller_runs
 | 
			
		||||
      # 线程池关闭过程的超时时间, 默认: PT10S
 | 
			
		||||
      executor-shutdown-timeout: PT10S
 | 
			
		||||
  # =============== end: 线程池配置 ===============
 | 
			
		||||
 | 
			
		||||
  # =============== start: user_connection repository 配置 ===============
 | 
			
		||||
  repository:
 | 
			
		||||
 | 
			
		||||
    # 第三方登录用户数据库表的字段 accessToken 与 refreshToken 加密专用密码
 | 
			
		||||
    text-encryptor-password: 7ca5d913a17b4942942d16a974e3fecc
 | 
			
		||||
    # 第三方登录用户数据库表的字段 accessToken 与 refreshToken 加密专用 salt
 | 
			
		||||
    text-encryptor-salt: cd538b1b077542aca5f86942b6507fe2
 | 
			
		||||
    # 是否在启动时检查并自动创建 userConnectionTableName 与 authTokenTableName, 默认: TRUE
 | 
			
		||||
    enableStartUpInitializeTable: true
 | 
			
		||||
    # 其他的有: 数据库表名称, 字段名称, curd sql 语句 等设置, 一般不需要更改,
 | 
			
		||||
    # 如果要添加字段: 具体查看 RepositoryProperties 与 Auth2JdbcUsersConnectionRepository
 | 
			
		||||
  # =============== end: user_connection repository 配置 ===============
 | 
			
		||||
 | 
			
		||||
    type: default
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user