优化管理后台的社交登录

This commit is contained in:
YunaiV 2022-07-05 22:00:23 +08:00
parent 2b9b302368
commit 8751471aa1
11 changed files with 75 additions and 137 deletions

View File

@ -141,23 +141,16 @@ public class AuthController {
@ApiImplicitParam(name = "type", value = "社交类型", required = true, dataTypeClass = Integer.class), @ApiImplicitParam(name = "type", value = "社交类型", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "redirectUri", value = "回调路径", dataTypeClass = String.class) @ApiImplicitParam(name = "redirectUri", value = "回调路径", dataTypeClass = String.class)
}) })
public CommonResult<String> socialAuthRedirect(@RequestParam("type") Integer type, public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
@RequestParam("redirectUri") String redirectUri) { @RequestParam("redirectUri") String redirectUri) {
return CommonResult.success(socialUserService.getAuthorizeUrl(type, redirectUri)); return CommonResult.success(socialUserService.getAuthorizeUrl(type, redirectUri));
} }
@PostMapping("/social-quick-login") @PostMapping("/social-login")
@ApiOperation("社交快捷登录,使用 code 授权码") @ApiOperation(value = "社交快捷登录,使用 code 授权码", notes = "适合未登录的用户,但是社交账号已绑定用户")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialQuickLoginReqVO reqVO) { public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) {
return success(authService.socialQuickLogin(reqVO)); return success(authService.socialLogin(reqVO));
}
@PostMapping("/social-bind-login")
@ApiOperation("社交绑定登录,使用 code 授权码 + 账号密码")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> socialBindLogin(@RequestBody @Valid AuthSocialBindLoginReqVO reqVO) {
return success(authService.socialBindLogin(reqVO));
} }
} }

View File

@ -1,5 +1,8 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo; package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -8,10 +11,11 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern; import javax.validation.constraints.Pattern;
@ApiModel("管理后台 - 账号密码登录 Request VO") @ApiModel(value = "管理后台 - 账号密码登录 Request VO", description = "如果登录并绑定社交用户,需要传递 social 开头的参数")
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@ -29,6 +33,8 @@ public class AuthLoginReqVO {
@Length(min = 4, max = 16, message = "密码长度为 4-16 位") @Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password; private String password;
// ========== 图片验证码相关 ==========
@ApiModelProperty(value = "验证码", required = true, example = "1024", notes = "验证码开启时,需要传递") @ApiModelProperty(value = "验证码", required = true, example = "1024", notes = "验证码开启时,需要传递")
@NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class) @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
private String code; private String code;
@ -37,9 +43,31 @@ public class AuthLoginReqVO {
@NotEmpty(message = "唯一标识不能为空", groups = CodeEnableGroup.class) @NotEmpty(message = "唯一标识不能为空", groups = CodeEnableGroup.class)
private String uuid; private String uuid;
// ========== 绑定社交登录时需要传递如下参数 ==========
@ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值")
@InEnum(SocialTypeEnum.class)
private Integer socialType;
@ApiModelProperty(value = "授权码", required = true, example = "1024")
private String socialCode;
@ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
private String socialState;
/** /**
* 开启验证码的 Group * 开启验证码的 Group
*/ */
public interface CodeEnableGroup {} public interface CodeEnableGroup {}
@AssertTrue(message = "授权码不能为空")
public boolean isSocialCodeValid() {
return socialType == null || StrUtil.isNotEmpty(socialCode);
}
@AssertTrue(message = "授权 state 不能为空")
public boolean isSocialState() {
return socialType == null || StrUtil.isNotEmpty(socialState);
}
} }

View File

@ -1,48 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
@ApiModel("管理后台 - 社交绑定登录 Request VO使用 code 授权码 + 账号密码")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthSocialBindLoginReqVO {
@ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 UserSocialTypeEnum 枚举值")
@InEnum(SocialTypeEnum.class)
@NotNull(message = "社交平台的类型不能为空")
private Integer type;
@ApiModelProperty(value = "授权码", required = true, example = "1024")
@NotEmpty(message = "授权码不能为空")
private String code;
@ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
@NotEmpty(message = "state 不能为空")
private String state;
@ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma")
@NotEmpty(message = "登录账号不能为空")
@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
private String username;
@ApiModelProperty(value = "密码", required = true, example = "buzhidao")
@NotEmpty(message = "密码不能为空")
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo; package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -12,12 +12,12 @@ import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 社交快捷登录 Request VO使用 code 授权") @ApiModel("管理后台 - 社交绑定登录 Request VO使用 code 授权码 + 账号密")
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder
public class AuthSocialQuickLoginReqVO { public class AuthSocialLoginReqVO {
@ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 UserSocialTypeEnum 枚举值") @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 UserSocialTypeEnum 枚举值")
@InEnum(SocialTypeEnum.class) @InEnum(SocialTypeEnum.class)

View File

@ -65,8 +65,7 @@ public interface AuthConvert {
return CollectionUtils.filterList(treeNodeMap.values(), node -> MenuIdEnum.ROOT.getId().equals(node.getParentId())); return CollectionUtils.filterList(treeNodeMap.values(), node -> MenuIdEnum.ROOT.getId().equals(node.getParentId()));
} }
SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialBindLoginReqVO reqVO); SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialLoginReqVO reqVO);
SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialQuickLoginReqVO reqVO);
SmsCodeSendReqDTO convert(AuthSmsSendReqVO reqVO); SmsCodeSendReqDTO convert(AuthSmsSendReqVO reqVO);

View File

@ -24,8 +24,7 @@ public class SecurityConfiguration {
registry.antMatchers(buildAdminApi("/system/auth/refresh-token")).permitAll(); registry.antMatchers(buildAdminApi("/system/auth/refresh-token")).permitAll();
// 社交登陆的接口 // 社交登陆的接口
registry.antMatchers(buildAdminApi("/system/auth/social-auth-redirect")).permitAll(); registry.antMatchers(buildAdminApi("/system/auth/social-auth-redirect")).permitAll();
registry.antMatchers(buildAdminApi("/system/auth/social-quick-login")).permitAll(); registry.antMatchers(buildAdminApi("/system/auth/social-login")).permitAll();
registry.antMatchers(buildAdminApi("/system/auth/social-bind-login")).permitAll();
// 登录登录的接口 // 登录登录的接口
registry.antMatchers(buildAdminApi("/system/auth/sms-login")).permitAll(); registry.antMatchers(buildAdminApi("/system/auth/sms-login")).permitAll();
registry.antMatchers(buildAdminApi("/system/auth/send-sms-code")).permitAll(); registry.antMatchers(buildAdminApi("/system/auth/send-sms-code")).permitAll();

View File

@ -60,15 +60,7 @@ public interface AdminAuthService {
* @param reqVO 登录信息 * @param reqVO 登录信息
* @return 登录结果 * @return 登录结果
*/ */
AuthLoginRespVO socialQuickLogin(@Valid AuthSocialQuickLoginReqVO reqVO); AuthLoginRespVO socialLogin(@Valid AuthSocialLoginReqVO reqVO);
/**
* 社交绑定登录使用 code 授权码 + 账号密码
*
* @param reqVO 登录信息
* @return 登录结果
*/
AuthLoginRespVO socialBindLogin(@Valid AuthSocialBindLoginReqVO reqVO);
/** /**
* 刷新访问令牌 * 刷新访问令牌

View File

@ -8,13 +8,14 @@ import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.system.service.common.CaptchaService; import cn.iocoder.yudao.module.system.service.common.CaptchaService;
import cn.iocoder.yudao.module.system.service.logger.LoginLogService; import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
@ -91,6 +92,12 @@ public class AdminAuthServiceImpl implements AdminAuthService {
// 使用账号密码进行登录 // 使用账号密码进行登录
AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword()); AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword());
// 如果 socialType 非空说明需要绑定社交用户
if (reqVO.getSocialType() != null) {
socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
}
// 创建 Token 令牌记录登录日志 // 创建 Token 令牌记录登录日志
return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME); return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
} }
@ -166,7 +173,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
} }
@Override @Override
public AuthLoginRespVO socialQuickLogin(AuthSocialQuickLoginReqVO reqVO) { public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) {
// 使用 code 授权码进行登录然后获得到绑定的用户编号 // 使用 code 授权码进行登录然后获得到绑定的用户编号
Long userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), Long userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
reqVO.getCode(), reqVO.getState()); reqVO.getCode(), reqVO.getState());
@ -184,18 +191,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL); return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
} }
@Override
public AuthLoginRespVO socialBindLogin(AuthSocialBindLoginReqVO reqVO) {
// 使用账号密码进行登录
AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword());
// 绑定社交用户
socialUserService.bindSocialUser(AuthConvert.INSTANCE.convert(user.getId(), getUserType().getValue(), reqVO));
// 创建 Token 令牌记录登录日志
return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
}
@Override @Override
public AuthLoginRespVO refreshToken(String refreshToken) { public AuthLoginRespVO refreshToken(String refreshToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT); OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT);

View File

@ -3,12 +3,15 @@ import {getRefreshToken} from "@/utils/auth";
import service from "@/utils/request"; import service from "@/utils/request";
// 登录方法 // 登录方法
export function login(username, password, code, uuid) { export function login(username, password, code, uuid,
socialType, socialCode, socialState) {
const data = { const data = {
username, username,
password, password,
code, code,
uuid uuid,
// 社交相关
socialType, socialCode, socialState
} }
return request({ return request({
url: '/system/auth/login', url: '/system/auth/login',
@ -51,9 +54,9 @@ export function socialAuthRedirect(type, redirectUri) {
} }
// 社交快捷登录,使用 code 授权码 // 社交快捷登录,使用 code 授权码
export function socialQuickLogin(type, code, state) { export function socialLogin(type, code, state) {
return request({ return request({
url: '/system/auth/social-quick-login', url: '/system/auth/social-login',
method: 'post', method: 'post',
data: { data: {
type, type,
@ -63,21 +66,6 @@ export function socialQuickLogin(type, code, state) {
}) })
} }
// 社交绑定登录,使用 code 授权码 + + 账号密码
export function socialBindLogin(type, code, state, username, password) {
return request({
url: '/system/auth/social-bind-login',
method: 'post',
data: {
type,
code,
state,
username,
password
}
})
}
// 获取登录验证码 // 获取登录验证码
export function sendSmsCode(mobile, scene) { export function sendSmsCode(mobile, scene) {
return request({ return request({

View File

@ -1,4 +1,4 @@
import {login, logout, getInfo, socialQuickLogin, socialBindLogin, smsLogin} from '@/api/login' import {login, logout, getInfo, socialLogin, socialBindLogin, smsLogin} from '@/api/login'
import {getAccessToken, setToken, removeToken, getRefreshToken} from '@/utils/auth' import {getAccessToken, setToken, removeToken, getRefreshToken} from '@/utils/auth'
const user = { const user = {
@ -38,8 +38,12 @@ const user = {
const password = userInfo.password const password = userInfo.password
const code = userInfo.code const code = userInfo.code
const uuid = userInfo.uuid const uuid = userInfo.uuid
const socialCode = userInfo.socialCode
const socialState = userInfo.socialState
const socialType = userInfo.socialType
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => { login(username, password, code, uuid,
socialType, socialCode, socialState).then(res => {
res = res.data; res = res.data;
// 设置 token // 设置 token
setToken(res) setToken(res)
@ -56,7 +60,7 @@ const user = {
const state = userInfo.state const state = userInfo.state
const type = userInfo.type const type = userInfo.type
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
socialQuickLogin(type, code, state).then(res => { socialLogin(type, code, state).then(res => {
res = res.data; res = res.data;
// 设置 token // 设置 token
setToken(res) setToken(res)
@ -67,25 +71,7 @@ const user = {
}) })
}, },
// 社交登录 // 短信登录
SocialLogin2({ commit }, userInfo) {
const code = userInfo.code
const state = userInfo.state
const type = userInfo.type
const username = userInfo.username.trim()
const password = userInfo.password
return new Promise((resolve, reject) => {
socialBindLogin(type, code, state, username, password).then(res => {
res = res.data;
// 设置 token
setToken(res)
resolve()
}).catch(error => {
reject(error)
})
})
},
// 登录
SmsLogin({ commit }, userInfo) { SmsLogin({ commit }, userInfo) {
const mobile = userInfo.mobile.trim() const mobile = userInfo.mobile.trim()
const mobileCode = userInfo.mobileCode const mobileCode = userInfo.mobileCode

View File

@ -87,6 +87,8 @@ export default {
username: "admin", username: "admin",
password: "admin123", password: "admin123",
rememberMe: false, rememberMe: false,
code: "",
uuid: "",
}, },
loginRules: { loginRules: {
username: [ username: [
@ -170,16 +172,20 @@ export default {
removeUsername() removeUsername()
removePassword() removePassword()
} }
this.$store.dispatch("SocialLogin2", { this.$store.dispatch("Login", {
code: this.code, socialCode: this.code,
state: this.state, socialState: this.state,
type: this.type, socialType: this.type,
//
username: this.loginForm.username, username: this.loginForm.username,
password: this.loginForm.password password: this.loginForm.password,
code: this.loginForm.code,
uuid: this.loginForm.uuid,
}).then(() => { }).then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(()=>{}); this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
}).catch(() => { }).catch(() => {
this.loading = false; this.loading = false;
this.getCode()
}); });
} }
}); });