仅供参考.不具有通用性.
首先,依赖文件中添加
1.13.2 1.3.2
me.zhyd.oauth JustAuth ${JustAuth.version} com.xkcoding.justauth justauth-spring-boot-starter ${justauth.version} org.springframework.boot spring-boot-starter-freemarker
resources文件夹下新建templates目录,新建thirdLogin.ftl用于做页面跳转.window.opener.postMessage("${token}", "*");与前端window.addEventListener('message', receiveMessage, false)对应. src/main/resources true src/main/java **/*.xml **/*.json **/*.ftl 用于查找templates中用于跳转的ftl文件
第三方登录 登陆中...
新建application-just.yml 用来单独存放justauth的配置信息
# 第三方登录 justauth: enabled: true extend: enum-class: com.alvis.exam.justauth.AuthExtendSource config: VPGIT: requestClass: com.alvis.exam.justauth.AuthVpGitRequest client-id: gitlab上为此application配置生成id client-secret: gitlab上为此application配置生成的secret redirect-uri: gitlab上配置的返回地址,如http://localhost:8081/xxxxx/xxx/xxxx/thirdLogin/xxgit/callback cache: # 缓存类型(default-使用JustAuth内置的缓存、redis-使用Redis缓存、custom-自定义缓存) type: default prefix: 'JUSTAUTH::STATE::' # 超时时长 timeout: 1h 修改application.yml配置 spring: profiles: active: ${spring.profiles.active} include: - just #配置freemarker freemarker: # 设置模板后缀名 suffix: .ftl # 设置文档类型 content-type: text/html # 设置页面编码格式 charset: UTF-8 # 设置页面缓存 cache: false prefer-file-system-access: false # 设置ftl文件路径 template-loader-path: - classpath:/templates settings: classic_compatible: true
自定义第三方认证扩展
public enum AuthExtendSource implements AuthSource { xxGIT { @Override public String authorize() { return "公司私服域名/gitlab/oauth/authorize"; } @Override public String accessToken() { return "公司私服域名/gitlab/oauth/token"; } @Override public String userInfo() { return "公司私服域名/gitlab/api/v4/user"; } } }
public class AuthxxGitRequest extends AuthDefaultRequest { public AuthVpGitRequest(AuthConfig config) { super(config, AuthExtendSource.xxGIT); } public AuthVpGitRequest(AuthConfig config, AuthStateCache authStateCache) { super(config, AuthExtendSource.xxGIT, authStateCache); } @Override protected AuthToken getAccessToken(AuthCallback authCallback) { HttpResponse response = this.doPostAuthorizationCode(authCallback.getCode()); JSONObject object = JSONObject.parseObject(response.body()); this.checkResponse(object); return AuthToken.builder().accessToken(object.getString("access_token")).refreshToken(object.getString("refresh_token")).idToken(object.getString("id_token")).tokenType(object.getString("token_type")).scope(object.getString("scope")).build(); } @Override protected AuthUser getUserInfo(AuthToken authToken) { HttpResponse response = this.doGetUserInfo(authToken); JSONObject object = JSONObject.parseObject(response.body()); this.checkResponse(object); return AuthUser.builder().uuid(object.getString("id")).username(object.getString("username")).nickname(object.getString("name")).avatar(object.getString("avatar_url")).blog(object.getString("web_url")).company(object.getString("organization")).location(object.getString("location")).email(object.getString("email")).remark(object.getString("bio")).gender(AuthUserGender.UNKNOWN).token(authToken).source(this.source.toString()).build(); } private void checkResponse(JSONObject object) { if (object.containsKey("error")) { throw new AuthException(object.getString("error_description")); } else if (object.containsKey("message")) { throw new AuthException(object.getString("message")); } } @Override public String authorize(String state) { return UrlBuilder.fromBaseUrl(super.authorize(state)).queryParam("scope", "read_user+openid+profile+email").build(); } }
controller层
@Controller @RequestMapping("/thirdLogin") @Slf4j public class ThirdLoginController { @Autowired private ISysUserService sysUserService; @Autowired private BaseCommonService baseCommonService; @Autowired private RedisUtil redisUtil; @Autowired private AuthRequestFactory factory; @RequestMapping("/render/{source}") public void render(@PathVariable("source") String source, HttpServletResponse response) throws IOException { log.info("第三方登录进入render:" + source); AuthRequest authRequest = factory.get(source); String authorizeUrl = authRequest.authorize(AuthStateUtils.createState()); log.info("第三方登录认证地址:" + authorizeUrl); response.sendRedirect(authorizeUrl); } @RequestMapping("/{source}/callback") public String login(@PathVariable("source") String source, AuthCallback callback,ModelMap modelMap) { log.info("第三方登录进入callback:" + source + " params:" + JSONObject.toJSONString(callback)); AuthRequest authRequest = factory.get(source); AuthResponse response = authRequest.login(callback); log.info(JSONObject.toJSONString(response)); VpResultresult = new VpResult (); if(response.getCode()==2000) { JSONObject data = JSONObject.parseObject(JSONObject.toJSONString(response.getData())); String username = data.getString("username"); String avatar = data.getString("avatar"); String uuid = data.getString("uuid"); //判断有没有这个人 LambdaQueryWrapper query = new LambdaQueryWrapper (); query.eq(SysUser::getThirdId, uuid); query.eq(SysUser::getThirdType, source); List thridList = sysUserService.list(query); SysUser user = null; if(thridList==null || thridList.size()==0) { user = new SysUser(); user.setActivitiSync(CommonConstant.ACT_SYNC_0); user.setDelFlag(CommonConstant.DEL_FLAG_0); user.setStatus(1); user.setThirdId(uuid); user.setThirdType(source); user.setAvatar(avatar); user.setUsername(uuid); user.setRealname(username); //设置初始密码 String salt = oConvertUtils.randomGen(8); user.setSalt(salt); String passwordEncode = PasswordUtil.encrypt(user.getUsername(), "123456", salt); user.setPassword(passwordEncode); sysUserService.saveThirdUser(user); }else { //已存在 只设置用户名 不设置头像 user = thridList.get(0); //user.setUsername(username); //sysUserService.updateById(user); } // 生成token String token = JwtUtil.sign(user.getUsername(), user.getPassword()); redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); // 设置超时时间 redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000); //update-begin-author:taoyan date:20200812 for:登录缓存用户信息 LoginUser redisUser = new LoginUser(); BeanUtils.copyProperties(user, redisUser); redisUser.setPassword(SecureUtil.md5(user.getPassword())); redisUtil.set(CacheConstant.SYS_USERS_CACHE_JWT +":" +token, redisUser); redisUtil.expire(CacheConstant.SYS_USERS_CACHE_JWT +":" +token, JwtUtil.EXPIRE_TIME*2 / 1000); //update-end-author:taoyan date:20200812 for:登录缓存用户信息 modelMap.addAttribute("token", token); //update-begin--Author:wangshuai Date:20200729 for:接口在签名校验失败时返回失败的标识码 issues#1441-------------------- }else{ modelMap.addAttribute("token", "登录失败"); } //update-end--Author:wangshuai Date:20200729 for:接口在签名校验失败时返回失败的标识码 issues#1441-------------------- result.setSuccess(false); result.setMessage("第三方登录异常,请联系管理员"); return "thirdLogin"; } @SuppressWarnings("unchecked") @RequestMapping(value = "/getLoginUser/{token}", method = RequestMethod.GET) @ResponseBody public VpResult getLoginUser(@PathVariable("token") String token) throws Exception { VpResult result = new VpResult (); String username = JwtUtil.getUsername(token); //1. 校验用户是否有效 SysUser sysUser = sysUserService.getUserByName(username); result = sysUserService.checkUserIsEffective(sysUser); if(!result.isSuccess()) { return result; } JSONObject obj = new JSONObject(); //用户登录信息 obj.put("userInfo", sysUser); //token 信息 obj.put("token", token); result.setDataInfo(obj); result.setSuccess(true); result.setReturnCode(200); baseCommonService.addLog("用户名: " + username + ",登录成功[第三方用户]!", CommonConstant.LOG_TYPE_1, null); return result; } }
注意vue.config.js下的网关映射
vue
methods中
/** * 第三方登录 * @param token * @returns {*} */ thirdLoginApi (token) { return axios({ url: process.env.VUE_APP_API + `/thirdLogin/getLoginUser/${token}`, method: 'get', headers: { 'Content-Type': 'application/json;charset=UTF-8' } }) }, ThirdLogin (token) { let that = this return new Promise((resolve, reject) => { console.log('token:', token) that.thirdLoginApi(token).then(response => { if (response.data.code === 1) { resolve(response) this.loginForm.password = response.userInfo.password console.log('success', response) } else { reject(response) console.log('failed') } }).catch(error => { reject(error) }) }).catch((e) => {}) }, // 第三方登录 onThirdLogin (source) { let url = process.env.VUE_APP_API + `/thirdLogin/render/${source}` window.open(url, `login ${source}`, 'height=500, width=500, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, resizable=no,location=n o, status=no') let that = this let receiveMessage = function (event) { var origin = event.origin console.log('origin', origin) let token = event.data console.log('event.data', token) that.ThirdLogin(token).then(result => { if (result && result.data.code === 1) { let _this = that this.loading = true _this.loginForm.userName = result.data.response.token console.log('username:', _this.loginForm.userName) _this.setUserName(_this.loginForm.userName) _this.loginForm.password = result.data.response.userInfo.password console.log('loginForm:', _this.loginForm) loginApi.login(_this.loginForm).then(function (result) { console.log('loginapi result', result) if (result && result.code === 1) { console.log('登陆成功') window.removeEventListener('message', receiveMessage, false) // 解除监听 _this.setUserName(_this.loginForm.userName) _this.$router.push({ path: '/' }) } else { _this.loading = false _this.$message.error(result.message) window.removeEventListener('message', receiveMessage, false) } }).catch(function (reason) { _this.loading = false }) } else { return false } }) } window.addEventListener('message', receiveMessage, false) },