diff --git a/maku-boot-system/src/main/java/net/maku/security/service/ThirdOpenIdServiceImpl.java b/maku-boot-system/src/main/java/net/maku/security/service/ThirdOpenIdServiceImpl.java new file mode 100644 index 0000000..0eccbbc --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/security/service/ThirdOpenIdServiceImpl.java @@ -0,0 +1,40 @@ +package net.maku.security.service; + +import lombok.AllArgsConstructor; +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 net.maku.framework.common.exception.ServerException; +import net.maku.framework.security.third.ThirdLogin; +import net.maku.framework.security.third.ThirdOpenIdService; +import net.maku.system.service.SysThirdLoginConfigService; +import org.springframework.stereotype.Service; + +/** + * 第三方登录,通过code,获取开放平台用户唯一标识 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class ThirdOpenIdServiceImpl implements ThirdOpenIdService { + private final SysThirdLoginConfigService sysThirdLoginConfigService; + + @Override + public String getOpenId(ThirdLogin login) { + AuthRequest authRequest = sysThirdLoginConfigService.getAuthRequest(login.getOpenType()); + AuthCallback callback = AuthCallback.builder().code(login.getCode()).state(login.getState()).build(); + + // 根据code,获取用户信息 + AuthResponse response = authRequest.login(callback); + + // 判断是否成功 + if (!response.ok()) { + throw new ServerException("第三方登录失败"); + } + + return response.getData().getUuid(); + } +} diff --git a/maku-boot-system/src/main/java/net/maku/security/service/ThirdUserDetailsServiceImpl.java b/maku-boot-system/src/main/java/net/maku/security/service/ThirdUserDetailsServiceImpl.java new file mode 100644 index 0000000..2c65dec --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/security/service/ThirdUserDetailsServiceImpl.java @@ -0,0 +1,37 @@ +package net.maku.security.service; + +import lombok.AllArgsConstructor; +import net.maku.framework.security.third.ThirdUserDetailsService; +import net.maku.system.convert.SysUserConvert; +import net.maku.system.dao.SysUserDao; +import net.maku.system.entity.SysUserEntity; +import net.maku.system.service.SysThirdLoginService; +import net.maku.system.service.SysUserDetailsService; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +/** + * 第三方登录,ThirdUserDetailsService + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class ThirdUserDetailsServiceImpl implements ThirdUserDetailsService { + private final SysUserDetailsService sysUserDetailsService; + private final SysThirdLoginService sysThirdLoginService; + private final SysUserDao sysUserDao; + + @Override + public UserDetails loadUserByOpenTypeAndOpenId(String openType, String openId) throws UsernameNotFoundException { + Long userId = sysThirdLoginService.getUserIdByOpenTypeAndOpenId(openType, openId); + SysUserEntity userEntity = sysUserDao.getById(userId); + if (userEntity == null) { + throw new UsernameNotFoundException("绑定的系统用户,不存在"); + } + + return sysUserDetailsService.getUserDetails(SysUserConvert.INSTANCE.convertDetail(userEntity)); + } +} diff --git a/maku-boot-system/src/main/java/net/maku/system/controller/SysAuthController.java b/maku-boot-system/src/main/java/net/maku/system/controller/SysAuthController.java index 86c96fd..131c288 100644 --- a/maku-boot-system/src/main/java/net/maku/system/controller/SysAuthController.java +++ b/maku-boot-system/src/main/java/net/maku/system/controller/SysAuthController.java @@ -68,6 +68,14 @@ public class SysAuthController { return Result.ok(token); } + @PostMapping("third") + @Operation(summary = "第三方登录") + public Result third(@RequestBody SysThirdCallbackVO login) { + SysUserTokenVO token = sysAuthService.loginByThird(login); + + return Result.ok(token); + } + @PostMapping("token") @Operation(summary = "获取 accessToken") public Result token(String refreshToken) { diff --git a/maku-boot-system/src/main/java/net/maku/system/controller/SysThirdLoginController.java b/maku-boot-system/src/main/java/net/maku/system/controller/SysThirdLoginController.java new file mode 100644 index 0000000..d541527 --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/system/controller/SysThirdLoginController.java @@ -0,0 +1,96 @@ +package net.maku.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AllArgsConstructor; +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 net.maku.framework.common.utils.Result; +import net.maku.framework.operatelog.annotations.OperateLog; +import net.maku.framework.operatelog.enums.OperateTypeEnum; +import net.maku.framework.security.user.SecurityUser; +import net.maku.system.service.SysThirdLoginConfigService; +import net.maku.system.service.SysThirdLoginService; +import net.maku.system.vo.SysThirdCallbackVO; +import net.maku.system.vo.SysThirdLoginVO; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 第三方账号登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/third") +@Tag(name = "第三方账号") +@AllArgsConstructor +public class SysThirdLoginController { + private final SysThirdLoginService sysThirdLoginService; + private final SysThirdLoginConfigService sysThirdLoginConfigService; + + @GetMapping("list") + @Operation(summary = "列表") + public Result> list() { + List list = sysThirdLoginService.listByUserId(SecurityUser.getUserId()); + + return Result.ok(list); + } + + @RequestMapping("render/{source}") + public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException { + AuthRequest authRequest = sysThirdLoginConfigService.getAuthRequest(source); + String authorizeUrl = authRequest.authorize(AuthStateUtils.createState()); + response.sendRedirect(authorizeUrl); + } + + @RequestMapping("/callback/{source}") + public ModelAndView login(@PathVariable("source") String source, AuthCallback callback) { + Map map = new HashMap<>(); + map.put("openType", source); + map.put("state", callback.getState()); + map.put("code", callback.getCode()); + + return new ModelAndView("third_login", map); + } + + @PostMapping("bind") + @Operation(summary = "绑定") + @OperateLog(type = OperateTypeEnum.INSERT) + public Result bind(@RequestBody SysThirdCallbackVO vo) { + AuthRequest authRequest = sysThirdLoginConfigService.getAuthRequest(vo.getOpenType()); + AuthCallback callback = AuthCallback.builder().code(vo.getCode()).state(vo.getState()).build(); + + // 根据code,获取用户信息 + AuthResponse response = authRequest.login(callback); + + // 判断是否成功 + if (!response.ok()) { + throw new RuntimeException("第三方登录失败"); + } + + // 绑定用户信息 + sysThirdLoginService.bind(SecurityUser.getUserId(), vo.getOpenType(), response.getData()); + + return Result.ok(); + } + + @PutMapping("unbind/{openType}") + @Operation(summary = "解绑") + @OperateLog(type = OperateTypeEnum.UPDATE) + public Result unBind(@PathVariable("openType") String openType) { + sysThirdLoginService.unBind(SecurityUser.getUserId(), openType); + + return Result.ok(); + } +} diff --git a/maku-boot-system/src/main/java/net/maku/system/convert/SysThirdLoginConvert.java b/maku-boot-system/src/main/java/net/maku/system/convert/SysThirdLoginConvert.java new file mode 100644 index 0000000..e075286 --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/system/convert/SysThirdLoginConvert.java @@ -0,0 +1,26 @@ +package net.maku.system.convert; + +import net.maku.system.entity.SysThirdLoginEntity; +import net.maku.system.vo.SysThirdLoginVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysThirdLoginConvert { + SysThirdLoginConvert INSTANCE = Mappers.getMapper(SysThirdLoginConvert.class); + + SysThirdLoginEntity convert(SysThirdLoginVO vo); + + SysThirdLoginVO convert(SysThirdLoginEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/maku-boot-system/src/main/java/net/maku/system/dao/SysThirdLoginDao.java b/maku-boot-system/src/main/java/net/maku/system/dao/SysThirdLoginDao.java new file mode 100644 index 0000000..3e79188 --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/system/dao/SysThirdLoginDao.java @@ -0,0 +1,16 @@ +package net.maku.system.dao; + +import net.maku.framework.mybatis.dao.BaseDao; +import net.maku.system.entity.SysThirdLoginEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysThirdLoginDao extends BaseDao { + +} \ No newline at end of file diff --git a/maku-boot-system/src/main/java/net/maku/system/entity/SysThirdLoginEntity.java b/maku-boot-system/src/main/java/net/maku/system/entity/SysThirdLoginEntity.java new file mode 100644 index 0000000..6912fa3 --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/system/entity/SysThirdLoginEntity.java @@ -0,0 +1,69 @@ +package net.maku.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.util.Date; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ + +@Data +@TableName("sys_third_login") +public class SysThirdLoginEntity { + /** + * id + */ + @TableId + private Long id; + + /** + * 开放平台类型 + */ + private String openType; + + /** + * 开放平台,唯一标识 + */ + private String openId; + + /** + * 昵称 + */ + private String username; + + /** + * 用户ID + */ + private Long userId; + + /** + * 租户ID + */ + private Long tenantId; + + /** + * 版本号 + */ + @Version + @TableField(fill = FieldFill.INSERT) + private Integer version; + + /** + * 删除标记 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private Integer deleted; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + +} \ No newline at end of file diff --git a/maku-boot-system/src/main/java/net/maku/system/enums/ThirdLoginEnum.java b/maku-boot-system/src/main/java/net/maku/system/enums/ThirdLoginEnum.java new file mode 100644 index 0000000..c62c180 --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/system/enums/ThirdLoginEnum.java @@ -0,0 +1,46 @@ +package net.maku.system.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 第三方登录枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum ThirdLoginEnum { + /** + * 企业微信 + */ + WECHAT_WORK("wechat_work"), + + /** + * 钉钉 + */ + DING_TALK("dingtalk"), + /** + * 飞书 + */ + FEI_SHU("feishu"), + + /** + * 微信开放平台 + */ + WECHAT_OPEN("wechat_open"); + + private final String value; + + public static ThirdLoginEnum toEnum(String value) { + for (ThirdLoginEnum item : values()) { + if (StrUtil.equalsIgnoreCase(item.getValue(), value)) { + return item; + } + } + + throw new IllegalArgumentException("Unsupported third login type: " + value); + } +} \ No newline at end of file diff --git a/maku-boot-system/src/main/java/net/maku/system/service/SysAuthService.java b/maku-boot-system/src/main/java/net/maku/system/service/SysAuthService.java index 6ec5c7f..d71010b 100644 --- a/maku-boot-system/src/main/java/net/maku/system/service/SysAuthService.java +++ b/maku-boot-system/src/main/java/net/maku/system/service/SysAuthService.java @@ -1,9 +1,6 @@ package net.maku.system.service; -import net.maku.system.vo.AccessTokenVO; -import net.maku.system.vo.SysAccountLoginVO; -import net.maku.system.vo.SysMobileLoginVO; -import net.maku.system.vo.SysUserTokenVO; +import net.maku.system.vo.*; /** * 权限认证服务 @@ -28,6 +25,13 @@ public interface SysAuthService { SysUserTokenVO loginByMobile(SysMobileLoginVO login); /** + * 第三方登录 + * + * @param login 登录信息 + */ + SysUserTokenVO loginByThird(SysThirdCallbackVO login); + + /** * 发送手机验证码 * * @param mobile 手机号 diff --git a/maku-boot-system/src/main/java/net/maku/system/service/SysThirdLoginService.java b/maku-boot-system/src/main/java/net/maku/system/service/SysThirdLoginService.java new file mode 100644 index 0000000..78add00 --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/system/service/SysThirdLoginService.java @@ -0,0 +1,33 @@ +package net.maku.system.service; + +import me.zhyd.oauth.model.AuthUser; +import net.maku.framework.mybatis.service.BaseService; +import net.maku.system.entity.SysThirdLoginEntity; +import net.maku.system.vo.SysThirdLoginVO; + +import java.util.List; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysThirdLoginService extends BaseService { + + List listByUserId(Long userId); + + void unBind(Long userId, String openType); + + void bind(Long userId, String openType, AuthUser authUser); + + /** + * 根据第三方登录类型和openId,查询用户Id + * + * @param openType 第三方登录类型 + * @param openId 第三方用户唯一标识 + * @return 用户Id + */ + Long getUserIdByOpenTypeAndOpenId(String openType, String openId); + +} \ No newline at end of file diff --git a/maku-boot-system/src/main/java/net/maku/system/service/impl/SysAuthServiceImpl.java b/maku-boot-system/src/main/java/net/maku/system/service/impl/SysAuthServiceImpl.java index 33ce42d..62c4c2c 100644 --- a/maku-boot-system/src/main/java/net/maku/system/service/impl/SysAuthServiceImpl.java +++ b/maku-boot-system/src/main/java/net/maku/system/service/impl/SysAuthServiceImpl.java @@ -1,12 +1,16 @@ package net.maku.system.service.impl; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.RandomUtil; import lombok.AllArgsConstructor; import net.maku.api.module.message.SmsApi; import net.maku.framework.common.constant.Constant; import net.maku.framework.common.exception.ServerException; import net.maku.framework.security.cache.TokenStoreCache; +import net.maku.framework.security.crypto.Sm2Util; import net.maku.framework.security.mobile.MobileAuthenticationToken; +import net.maku.framework.security.third.ThirdAuthenticationToken; +import net.maku.framework.security.third.ThirdLogin; import net.maku.framework.security.user.UserDetail; import net.maku.system.enums.LoginOperationEnum; import net.maku.system.service.*; @@ -49,7 +53,7 @@ public class SysAuthServiceImpl implements SysAuthService { try { // 用户认证 authentication = authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken(login.getUsername(), login.getPassword())); + new UsernamePasswordAuthenticationToken(login.getUsername(), Sm2Util.decrypt(login.getPassword()))); } catch (BadCredentialsException e) { throw new ServerException("用户名或密码错误"); } @@ -90,6 +94,31 @@ public class SysAuthServiceImpl implements SysAuthService { } @Override + public SysUserTokenVO loginByThird(SysThirdCallbackVO login) { + Authentication authentication; + try { + // 转换对象 + ThirdLogin thirdLogin = BeanUtil.copyProperties(login, ThirdLogin.class); + + // 用户认证 + authentication = authenticationManager.authenticate(new ThirdAuthenticationToken(thirdLogin)); + } catch (BadCredentialsException e) { + throw new ServerException("第三方登录失败"); + } + + // 用户信息 + UserDetail user = (UserDetail) authentication.getPrincipal(); + + // 生成 accessToken + SysUserTokenVO userTokenVO = sysUserTokenService.createToken(user.getId()); + + // 保存用户信息到缓存 + tokenStoreCache.saveUser(userTokenVO.getAccessToken(), user); + + return userTokenVO; + } + + @Override public boolean sendCode(String mobile) { // 生成6位验证码 String code = RandomUtil.randomNumbers(6); diff --git a/maku-boot-system/src/main/java/net/maku/system/service/impl/SysThirdLoginServiceImpl.java b/maku-boot-system/src/main/java/net/maku/system/service/impl/SysThirdLoginServiceImpl.java new file mode 100644 index 0000000..700da1b --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/system/service/impl/SysThirdLoginServiceImpl.java @@ -0,0 +1,62 @@ +package net.maku.system.service.impl; + +import com.aliyun.oss.ServiceException; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import me.zhyd.oauth.model.AuthUser; +import net.maku.framework.mybatis.service.impl.BaseServiceImpl; +import net.maku.system.convert.SysThirdLoginConvert; +import net.maku.system.dao.SysThirdLoginDao; +import net.maku.system.entity.SysThirdLoginEntity; +import net.maku.system.service.SysThirdLoginService; +import net.maku.system.vo.SysThirdLoginVO; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysThirdLoginServiceImpl extends BaseServiceImpl implements SysThirdLoginService { + + @Override + public List listByUserId(Long userId) { + List list = baseMapper.selectList( + Wrappers.lambdaQuery().eq(SysThirdLoginEntity::getUserId, userId)); + + return SysThirdLoginConvert.INSTANCE.convertList(list); + } + + @Override + public void unBind(Long userId, String openType) { + baseMapper.delete(Wrappers.lambdaQuery(). + eq(SysThirdLoginEntity::getUserId, userId).eq(SysThirdLoginEntity::getOpenType, openType)); + } + + @Override + public void bind(Long userId, String openType, AuthUser authUser) { + SysThirdLoginEntity entity = new SysThirdLoginEntity(); + entity.setUserId(userId); + entity.setOpenType(openType); + entity.setOpenId(authUser.getUuid()); + entity.setUsername(authUser.getUsername()); + + baseMapper.insert(entity); + } + + @Override + public Long getUserIdByOpenTypeAndOpenId(String openType, String openId) { + SysThirdLoginEntity entity = baseMapper.selectOne(Wrappers.lambdaQuery() + .eq(SysThirdLoginEntity::getOpenType, openType).eq(SysThirdLoginEntity::getOpenId, openId)); + if (entity == null) { + throw new ServiceException("还未绑定用户,请先绑定用户"); + } + + return entity.getUserId(); + } +} \ No newline at end of file diff --git a/maku-boot-system/src/main/java/net/maku/system/vo/SysThirdCallbackVO.java b/maku-boot-system/src/main/java/net/maku/system/vo/SysThirdCallbackVO.java new file mode 100644 index 0000000..59c73e0 --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/system/vo/SysThirdCallbackVO.java @@ -0,0 +1,27 @@ +package net.maku.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 第三方登录 回调参数 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "第三方登录 回调参数") +public class SysThirdCallbackVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "开放平台类型") + private String openType; + + @Schema(description = "开放平台Code") + private String code; + + @Schema(description = "state") + private String state; +} diff --git a/maku-boot-system/src/main/java/net/maku/system/vo/SysThirdLoginVO.java b/maku-boot-system/src/main/java/net/maku/system/vo/SysThirdLoginVO.java new file mode 100644 index 0000000..65150fe --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/system/vo/SysThirdLoginVO.java @@ -0,0 +1,43 @@ +package net.maku.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.maku.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.util.Date; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "第三方登录") +public class SysThirdLoginVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "开放平台类型") + private String openType; + + @Schema(description = "开放平台,唯一标识") + private String openId; + + @Schema(description = "昵称") + private String username; + + @Schema(description = "用户ID") + private Long userId; + + @Schema(description = "租户ID") + private Long tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private Date createTime; +} \ No newline at end of file diff --git a/maku-boot-system/src/main/resources/auth.yml b/maku-boot-system/src/main/resources/auth.yml index 2f667da..a16e12e 100644 --- a/maku-boot-system/src/main/resources/auth.yml +++ b/maku-boot-system/src/main/resources/auth.yml @@ -6,5 +6,8 @@ auth: - /sys/auth/token - /sys/auth/send/code - /sys/auth/mobile + - /sys/auth/third + - /sys/third/callback/** + - /sys/third/render/** - /upload/** - / \ No newline at end of file diff --git a/maku-boot-system/src/main/resources/templates/third_login.ftlh b/maku-boot-system/src/main/resources/templates/third_login.ftlh new file mode 100644 index 0000000..5ddf0bd --- /dev/null +++ b/maku-boot-system/src/main/resources/templates/third_login.ftlh @@ -0,0 +1,24 @@ + + + + + + + 第三方登录 + + +登陆中... + + + \ No newline at end of file