diff --git a/adc-da-login/src/main/java/com/adc/da/login/rest/LoginRestController.java b/adc-da-login/src/main/java/com/adc/da/login/rest/LoginRestController.java index 0edb2ef..1ebdb06 100644 --- a/adc-da-login/src/main/java/com/adc/da/login/rest/LoginRestController.java +++ b/adc-da-login/src/main/java/com/adc/da/login/rest/LoginRestController.java @@ -1,5 +1,6 @@ package com.adc.da.login.rest; +import cn.hutool.core.util.StrUtil; import com.adc.da.log.annotation.BusinessLog; import com.adc.da.login.entity.OnlineUserEO; import com.adc.da.login.security.SystemAuthorizingRealm; @@ -507,6 +508,20 @@ public class LoginRestController { return Result.success(); } + @GetMapping("/ssoLogin") + @ResponseBody + @ApiOperation(value = "SSO,根据Code返回用户信息") + public ResponseMessage ssoLogin(String code, HttpServletRequest request){ + if (StrUtil.isBlank(code)) { + return Result.error("无法单点登录,code为空"); + } + String username = userService.ssoLogin(code); + + UsernamePasswordToken token = new UsernamePasswordToken(username); + + return login(request, token); + } + public static void main(String[] args) throws Exception { String decrypt = EncryptUtil.decrypt("F6lnqMmPc/zkC8LcdSnDIMkH3Pt3DC1/53blM5P0FkM="); System.out.println(decrypt); diff --git a/adc-da-sys/src/main/java/com/adc/da/sys/constant/SsoConstants.java b/adc-da-sys/src/main/java/com/adc/da/sys/constant/SsoConstants.java new file mode 100644 index 0000000..c9f3764 --- /dev/null +++ b/adc-da-sys/src/main/java/com/adc/da/sys/constant/SsoConstants.java @@ -0,0 +1,55 @@ +package com.adc.da.sys.constant; + +/** + * @author: CaiHaohan + * @Date: 2023/5/17 14:02 + * @Description: SSO单点登录所需常量 + */ +public class SsoConstants { + + /** + * 获取Token的路径 + */ + public static final String GET_TOKEN_PATH = "esc-sso/oauth2.0/accessToken?"; + + /** + * 获取Token的路径 + */ + public static final String GET_USERINFO_PATH = "esc-sso/oauth2.0/profile?"; + + /** + * 应用注册ID + */ + public static final String CLIENT_ID = "client_id="; + + /** + * 属性常量 + */ + public static final String GRANT_TYPE = "grant_type="; + + /** + * 属性常量 + */ + public static final String AUTHORIZATION_CODE = "authorization_code"; + + /** + * 接受到的code值 + */ + public static final String CODE = "code="; + + /** + * client_secret + */ + public static final String CLIENT_SECRET = "client_secret="; + + /** + * 应用回调地址,需要http格式化 + */ + public static final String REDIRECT_URI = "redirect_uri="; + + /** + * 获取的token的值 必须 + */ + public static final String ACCESS_TOKEN = "access_token="; + +} diff --git a/adc-da-sys/src/main/java/com/adc/da/sys/service/UserEOServiceImpl.java b/adc-da-sys/src/main/java/com/adc/da/sys/service/UserEOServiceImpl.java index e616a1a..7c17193 100644 --- a/adc-da-sys/src/main/java/com/adc/da/sys/service/UserEOServiceImpl.java +++ b/adc-da-sys/src/main/java/com/adc/da/sys/service/UserEOServiceImpl.java @@ -1,5 +1,9 @@ package com.adc.da.sys.service; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.json.JSONUtil; +import com.adc.da.sys.constant.SsoConstants; import com.adc.da.sys.constant.SysConstants; import com.adc.da.sys.constant.UserBelongEnum; import com.adc.da.sys.dao.mysql.UserEODao; @@ -10,12 +14,15 @@ import com.adc.da.sys.service.iservice.IUserEoService; import com.adc.da.sys.util.EncryptUtil; import com.adc.da.sys.vo.UserImportVO; import com.adc.da.sys.vo.UserVO; +import com.adc.da.sys.vo.iam.SsoResponse; +import com.adc.da.sys.vo.iam.SsoUserInfoResponse; import com.adc.da.util.exception.AdcDaBaseException; import com.adc.da.util.utils.CollectionUtils; import com.adc.da.util.utils.StringUtils; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -36,6 +43,7 @@ import java.util.stream.Collectors; */ @Service("userEOService") @Transactional +@Slf4j public class UserEOServiceImpl implements IUserEoService { @@ -54,6 +62,15 @@ public class UserEOServiceImpl implements IUserEoService { @Resource private RoleEOService roleEOService; + @Value("${sso.clientId}") + private String ssoClientId; + + @Value("${sso.clientSecret}") + private String ssoClientSecret; + + @Value("${sso.url}") + private String ssoUrl; + /** * 获取角色信息,用户名,用于新增用户校验 @@ -342,6 +359,64 @@ public class UserEOServiceImpl implements IUserEoService { return dao.getOwnLeader(orgEOList); } + /** + * 获取【通过Code获取accessToken接口】的Url + * @param code code + * @return Url + */ + private String getTokenByCodeUrl(String code) { + return ssoUrl + SsoConstants.GET_TOKEN_PATH + + SsoConstants.GRANT_TYPE + SsoConstants.AUTHORIZATION_CODE + "&" + + SsoConstants.CLIENT_ID + ssoClientId + "&" + + SsoConstants.CLIENT_SECRET + ssoClientSecret + "&" + + SsoConstants.CODE + code + "&" + + SsoConstants.REDIRECT_URI + "XXX"; + } + + /** + * 获取【通过accessToken获取用户信息接口】的Url + * @param accessToken accessToken + * @return Url + */ + private String getUserInfoByTokenUrl(String accessToken) { + return ssoUrl + SsoConstants.GET_USERINFO_PATH + + SsoConstants.ACCESS_TOKEN + accessToken; + } + + @Override + public String ssoLogin(String code) { + //向SSO服务器发送code获取用户token + String getTokenByCodeUrl = getTokenByCodeUrl(code); + + String tokenResponse = HttpRequest.post(getTokenByCodeUrl).execute().body(); + + SsoResponse tokenResponseObject = JSONUtil.toBean(tokenResponse, SsoResponse.class); + //获取返回值中的token + String accessToken = tokenResponseObject.getAccess_token(); + + //向SSO服务器发送token获取用户数据 + if (StrUtil.isBlank(accessToken)) { + log.info("通过code获取accessToken失败"); + throw new AdcDaBaseException("通过code获取accessToken失败"); + } + + String getUserInfoByTokenUrl = getUserInfoByTokenUrl(accessToken); + String userInfoResponse = HttpRequest.get(getUserInfoByTokenUrl).execute().body(); + + SsoUserInfoResponse userInfoResponseObject = JSONUtil.toBean(userInfoResponse, SsoUserInfoResponse.class); + + //获取返回值中的用户id + String userId = userInfoResponseObject.getId(); + + //根据用户id取出用户名 + UserEO user = getUserById(userId); + if (user == null) { + log.info("根据用户id取出用户失败"); + throw new AdcDaBaseException("根据用户id取出用户失败"); + } + return user.getUsname(); + } + void checkExcel(List list) { if (CollectionUtils.isEmpty(list)) { throw new AdcDaBaseException("数据不能为空"); diff --git a/adc-da-sys/src/main/java/com/adc/da/sys/service/iservice/IUserEoService.java b/adc-da-sys/src/main/java/com/adc/da/sys/service/iservice/IUserEoService.java index 35824d6..1732fed 100644 --- a/adc-da-sys/src/main/java/com/adc/da/sys/service/iservice/IUserEoService.java +++ b/adc-da-sys/src/main/java/com/adc/da/sys/service/iservice/IUserEoService.java @@ -70,4 +70,12 @@ public interface IUserEoService { UserVO getUserByIdNodel(String userId); List getOwnLeader(List orgEOList); + + /** + * IAM单点登录逻辑 + * + * @param code + * @return + */ + String ssoLogin(String code); } diff --git a/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/SsoResponse.java b/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/SsoResponse.java new file mode 100644 index 0000000..cd566b7 --- /dev/null +++ b/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/SsoResponse.java @@ -0,0 +1,26 @@ +package com.adc.da.sys.vo.iam; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author: CaiHaohan + * @Date: 2023/5/17 14:22 + * @Description: + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SsoResponse { + + /** + * 返回的token 必须 + */ + private String access_token; + + /** + * 刷新token(在应用配置里,打开【token刷新】的开关,即可返回该参数) 非必须 + */ + private String refresh_token; +} diff --git a/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/SsoUserInfo.java b/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/SsoUserInfo.java new file mode 100644 index 0000000..ea75078 --- /dev/null +++ b/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/SsoUserInfo.java @@ -0,0 +1,25 @@ +package com.adc.da.sys.vo.iam; + +import cn.hutool.system.UserInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author: CaiHaohan + * @Date: 2023/5/17 15:04 + * @Description: + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SsoUserInfo { + + private String account_no; + + private String token_expired; + + private String token_gtime; + + private UserDetailInfo user_detail_info; +} diff --git a/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/SsoUserInfoResponse.java b/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/SsoUserInfoResponse.java new file mode 100644 index 0000000..698f7e2 --- /dev/null +++ b/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/SsoUserInfoResponse.java @@ -0,0 +1,23 @@ +package com.adc.da.sys.vo.iam; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author: CaiHaohan + * @Date: 2023/5/17 15:08 + * @Description: + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SsoUserInfoResponse { + + /** + * 用户id + */ + private String id; + + private SsoUserInfo attributes; +} diff --git a/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/UserDetailInfo.java b/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/UserDetailInfo.java new file mode 100644 index 0000000..8921572 --- /dev/null +++ b/adc-da-sys/src/main/java/com/adc/da/sys/vo/iam/UserDetailInfo.java @@ -0,0 +1,22 @@ +package com.adc.da.sys.vo.iam; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author: CaiHaohan + * @Date: 2023/5/17 15:06 + * @Description: + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserDetailInfo { + + private List jobs; + private List userTypes; + private List orgs; +}