#238 飞书扫码登录失败

This commit is contained in:
MaxKey 2024-11-25 07:38:47 +08:00
parent 3ee742d8eb
commit 7efa9dd9f5
12 changed files with 127 additions and 146 deletions

View File

@ -119,7 +119,7 @@ public class AuthJwtService {
* @return true or false
*/
public boolean validateJwtToken(String authToken) {
if(StringUtils.isNotBlank(authToken)) {
if(StringUtils.isNotBlank(authToken) && authToken.length() > 20) {
try {
JWTClaimsSet claims = resolve(authToken);
boolean isExpiration = claims.getExpirationTime().after(DateTime.now().toDate());

View File

@ -64,7 +64,7 @@ public class PermissionInterceptor implements AsyncHandlerInterceptor {
SignPrincipal principal = AuthorizationUtils.getPrincipal();
//判断用户是否登录,判断用户是否登录用户
if(principal == null){
_logger.trace("No Authentication ... forward to /auth/entrypoint , request URI " + request.getRequestURI());
_logger.debug("No Authentication ... forward to /auth/entrypoint , request URI {}" , request.getRequestURI());
RequestDispatcher dispatcher = request.getRequestDispatcher("/auth/entrypoint");
dispatcher.forward(request, response);
return false;

View File

@ -107,11 +107,11 @@ public class AbstractSocialSignOnEndpoint {
}
AuthResponse<?> authResponse=authRequest.login(authCallback);
_logger.debug("Response : " + authResponse.getData());
_logger.debug("Response : {}" , authResponse.getData());
String socialUserId = socialSignOnProviderService.getAccountId(provider, authResponse);
socialsAssociate =new SocialsAssociate();
socialsAssociate.setProvider(provider);
socialsAssociate.setSocialUserId(
socialSignOnProviderService.getAccountId(provider, authResponse));
socialsAssociate.setSocialUserId(socialUserId);
socialsAssociate.setInstId(instId);
return socialsAssociate;

View File

@ -35,7 +35,6 @@ import org.dromara.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
@ -47,17 +46,14 @@ import java.util.Map;
* @author Crystal.Sea
*
*/
@Controller
@RestController
@RequestMapping(value = "/logon/oauth20")
public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
static final Logger _logger = LoggerFactory.getLogger(SocialSignOnEndpoint.class);
@RequestMapping(value={"/authorize/{provider}"}, method = RequestMethod.GET)
@ResponseBody
public Message<Object> authorize( HttpServletRequest request,
@PathVariable("provider") String provider
) {
_logger.trace("SocialSignOn provider : " + provider);
@GetMapping("/authorize/{provider}")
public Message<Object> authorize( HttpServletRequest request,@PathVariable("provider") String provider) {
_logger.trace("SocialSignOn provider : {}" , provider);
String instId = WebContext.getInst().getId();
String originURL =WebContext.getContextPath(request,false);
String authorizationUrl =
@ -67,14 +63,12 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
originURL + applicationConfig.getFrontendUri()
).authorize(authTokenService.genRandomJwt());
_logger.trace("authorize SocialSignOn : " + authorizationUrl);
return new Message<Object>((Object)authorizationUrl);
_logger.trace("authorize SocialSignOn : {}" , authorizationUrl);
return new Message<Object>(authorizationUrl);
}
@RequestMapping(value={"/scanqrcode/{provider}"}, method = RequestMethod.GET)
@ResponseBody
public Message<SocialsProvider> scanQRCode(HttpServletRequest request,
@PathVariable("provider") String provider) {
@GetMapping("/scanqrcode/{provider}")
public Message<SocialsProvider> scanQRCode(HttpServletRequest request,@PathVariable("provider") String provider) {
String instId = WebContext.getInst().getId();
String originURL =WebContext.getContextPath(request,false);
AuthRequest authRequest =
@ -82,16 +76,14 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
instId,
provider,
originURL + applicationConfig.getFrontendUri());
if(authRequest == null ) {
_logger.error("build authRequest fail .");
}
SocialsProvider scanQrProvider = null;
if(authRequest != null ) {
String state = UUID.generate().toString();
//String state = authTokenService.genRandomJwt();
authRequest.authorize(state);
SocialsProvider socialSignOnProvider = socialSignOnProviderService.get(instId,provider);
SocialsProvider scanQrProvider = new SocialsProvider(socialSignOnProvider);
scanQrProvider = new SocialsProvider(socialSignOnProvider);
scanQrProvider.setState(state);
scanQrProvider.setRedirectUri(
socialSignOnProviderService.getRedirectUri(
@ -100,12 +92,14 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
if (provider.equalsIgnoreCase(AuthMaxkeyRequest.KEY)) {
socialSignOnProviderService.setToken(state);
}
return new Message<SocialsProvider>(scanQrProvider);
}else {
_logger.error("build authRequest fail .");
}
return new Message<>(scanQrProvider);
}
@RequestMapping(value={"/bind/{provider}"}, method = RequestMethod.GET)
@GetMapping("/bind/{provider}")
public Message<AuthJwt> bind(@PathVariable("provider") String provider,
@CurrentUser UserInfo userInfo,
HttpServletRequest request) {
@ -118,24 +112,18 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
socialsAssociate.setUserId(userInfo.getId());
socialsAssociate.setUsername(userInfo.getUsername());
socialsAssociate.setInstId(userInfo.getInstId());
//socialsAssociate.setAccessToken(JsonUtils.object2Json(accessToken));
//socialsAssociate.setExAttribute(JsonUtils.object2Json(accessToken.getResponseObject()));
_logger.debug("Social Bind : "+socialsAssociate);
_logger.debug("Social Bind : {}",socialsAssociate);
this.socialsAssociateService.delete(socialsAssociate);
this.socialsAssociateService.insert(socialsAssociate);
return new Message<AuthJwt>();
return new Message<>();
}catch(Exception e) {
_logger.error("callback Exception ",e);
}
return new Message<AuthJwt>(Message.ERROR);
return new Message<>(Message.ERROR);
}
@RequestMapping(value={"/callback/{provider}"}, method = RequestMethod.GET)
public Message<AuthJwt> callback(@PathVariable("provider") String provider,
HttpServletRequest request) {
@GetMapping("/callback/{provider}")
public Message<AuthJwt> callback(@PathVariable("provider") String provider,HttpServletRequest request) {
//auth call back may exception
try {
String originURL =WebContext.getContextPath(request,false);
@ -145,36 +133,38 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
SocialsAssociate socialssssociate1 = this.socialsAssociateService.get(socialsAssociate);
_logger.debug("Loaded SocialSignOn Socials Associate : "+socialssssociate1);
_logger.debug("Loaded SocialSignOn Socials Associate : {}",socialssssociate1);
if (null == socialssssociate1) {
//如果存在第三方ID并且在数据库无法找到映射关系则进行绑定逻辑
if (StringUtils.isNotEmpty(socialsAssociate.getSocialUserId())) {
//返回message为第三方用户标识
return new Message<AuthJwt>(Message.PROMPT,socialsAssociate.getSocialUserId());
return new Message<>(Message.PROMPT,socialsAssociate.getSocialUserId());
}
}
socialsAssociate = socialssssociate1;
if(socialsAssociate != null) {
_logger.debug("Social Sign On from {} mapping to user {}",
socialsAssociate.getProvider(),socialsAssociate.getUsername());
LoginCredential loginCredential =new LoginCredential(
socialsAssociate.getUsername(),"",ConstsLoginType.SOCIALSIGNON);
SocialsProvider socialSignOnProvider = socialSignOnProviderService.get(instId,provider);
loginCredential.setProvider(socialSignOnProvider.getProviderName());
Authentication authentication = authenticationProvider.authenticate(loginCredential,true);
//socialsAssociate.setAccessToken(JsonUtils.object2Json(this.accessToken));
socialsAssociate.setSocialUserInfo(accountJsonString);
//socialsAssociate.setExAttribute(JsonUtils.object2Json(accessToken.getResponseObject()));
this.socialsAssociateService.update(socialsAssociate);
return new Message<AuthJwt>(authTokenService.genAuthJwt(authentication));
return new Message<>(authTokenService.genAuthJwt(authentication));
}else {
}
}catch(Exception e) {
_logger.error("callback Exception ",e);
return new Message<AuthJwt>(Message.ERROR);
}
return new Message<>(Message.ERROR);
}
@ -182,14 +172,14 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
* 提供给第三方应用关联用户接口
* @return
*/
@RequestMapping(value={"/workweixin/qr/auth/login"}, method = {RequestMethod.POST})
@PostMapping("/workweixin/qr/auth/login")
public Message<AuthJwt> qrAuthLogin(
@RequestParam Map<String, String> param,
HttpServletRequest request) {
try {
if (null == param){
return new Message<AuthJwt>(Message.ERROR);
return new Message<>(Message.ERROR);
}
String token = param.get("token");
String username = param.get("username");
@ -199,15 +189,15 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
//设置token和用户绑定
boolean flag = this.socialSignOnProviderService.bindtoken(token,username);
if (flag) {
return new Message<AuthJwt>();
return new Message<>();
}
} else {
return new Message<AuthJwt>(Message.WARNING,"Invalid token");
return new Message<>(Message.WARNING,"Invalid token");
}
}catch(Exception e) {
_logger.error("qrAuthLogin Exception ",e);
}
return new Message<AuthJwt>(Message.ERROR);
return new Message<>(Message.ERROR);
}
@ -218,23 +208,23 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
* @param request
* @return
*/
@RequestMapping(value={"/qrcallback/{provider}/{state}"}, method = RequestMethod.GET)
@PostMapping("/qrcallback/{provider}/{state}")
public Message<AuthJwt> qrcallback(@PathVariable("provider") String provider,@PathVariable("state") String state,
HttpServletRequest request) {
try {
//判断只有maxkey扫码
if (!provider.equalsIgnoreCase(AuthMaxkeyRequest.KEY)) {
return new Message<AuthJwt>(Message.ERROR);
return new Message<>(Message.ERROR);
}
String loginName = socialSignOnProviderService.getToken(state);
if (StringUtils.isEmpty(loginName)) {
//二维码过期
return new Message<AuthJwt>(Message.PROMPT);
return new Message<>(Message.PROMPT);
}
if("-1".equalsIgnoreCase(loginName)){
//暂无用户扫码
return new Message<AuthJwt>(Message.WARNING);
return new Message<>(Message.WARNING);
}
String instId = WebContext.getInst().getId();
@ -246,29 +236,25 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
socialsAssociate = this.socialsAssociateService.get(socialsAssociate);
_logger.debug("qrcallback Loaded SocialSignOn Socials Associate : "+socialsAssociate);
_logger.debug("qrcallback Loaded SocialSignOn Socials Associate : {}",socialsAssociate);
if(null == socialsAssociate) {
return new Message<AuthJwt>(Message.ERROR);
return new Message<>(Message.ERROR);
}
_logger.debug("qrcallback Social Sign On from {} mapping to user {}", socialsAssociate.getProvider(),socialsAssociate.getUsername());
LoginCredential loginCredential =new LoginCredential(
socialsAssociate.getUsername(),"",ConstsLoginType.SOCIALSIGNON);
SocialsProvider socialSignOnProvider = socialSignOnProviderService.get(instId,provider);
loginCredential.setProvider(socialSignOnProvider.getProviderName());
Authentication authentication = authenticationProvider.authenticate(loginCredential,true);
//socialsAssociate.setAccessToken(JsonUtils.object2Json(this.accessToken));
socialsAssociate.setSocialUserInfo(accountJsonString);
//socialsAssociate.setExAttribute(JsonUtils.object2Json(accessToken.getResponseObject()));
this.socialsAssociateService.update(socialsAssociate);
return new Message<AuthJwt>(authTokenService.genAuthJwt(authentication));
return new Message<>(authTokenService.genAuthJwt(authentication));
}catch(Exception e) {
_logger.error("qrcallback Exception ",e);
return new Message<AuthJwt>(Message.ERROR);
return new Message<>(Message.ERROR);
}
}
}

View File

@ -43,7 +43,7 @@ import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.*;
public class SocialSignOnProviderService{
private static Logger _logger = LoggerFactory.getLogger(SocialSignOnProviderService.class);
private static final Logger _logger = LoggerFactory.getLogger(SocialSignOnProviderService.class);
private static final String DEFAULT_SELECT_STATEMENT = "select * from mxk_socials_provider where instid = ? and status = 1 order by sortindex";
@ -52,7 +52,7 @@ public class SocialSignOnProviderService{
.expireAfterWrite(ConstsTimeInterval.ONE_HOUR, TimeUnit.MINUTES)
.build();
HashMap<String ,SocialsProvider>socialSignOnProviderMaps = new HashMap<String ,SocialsProvider>();
HashMap<String ,SocialsProvider>socialSignOnProviderMaps = new HashMap<>();
private final JdbcTemplate jdbcTemplate;
@ -199,9 +199,9 @@ public class SocialSignOnProviderService{
List<SocialsProvider> listSocialsProvider = jdbcTemplate.query(
DEFAULT_SELECT_STATEMENT,
new SocialsProviderRowMapper(),instId);
_logger.trace("query SocialsProvider " + listSocialsProvider);
_logger.trace("query SocialsProvider {}" , listSocialsProvider);
List<SocialsProvider> socialSignOnProviders = new ArrayList<SocialsProvider>();
List<SocialsProvider> socialSignOnProviders = new ArrayList<>();
socialsLogin = new SocialsProviderLogin(socialSignOnProviders);
for(SocialsProvider socialsProvider : listSocialsProvider){
_logger.debug("Social Provider {} ({})" ,

View File

@ -107,14 +107,14 @@ export class DefaultInterceptor implements HttpInterceptor {
*/
private refreshTokenRequest(): Observable<any> {
const model = this.tokenSrv.get();
return this.http.post(`/auth/token/refresh`, null, { refresh_token: model?.['refresh_token'] || '' });
return this.http.post(`/auth/token/refresh?_allow_anonymous=true`, null, { refresh_token: model?.['refresh_token'] || '' });
}
// #region 刷新Token方式一使用 401 重新刷新 Token
private tryRefreshToken(ev: HttpResponseBase, req: HttpRequest<any>, next: HttpHandler): Observable<any> {
// 1、若请求为刷新Token请求表示来自刷新Token可以直接跳转登录页
if ([`/auth/token/refresh`].some(url => req.url.includes(url))) {
if ([`/auth/token/refresh?_allow_anonymous=true`].some(url => req.url.includes(url))) {
this.toLogin();
return throwError(ev);
}

View File

@ -19,9 +19,10 @@ import { ActivatedRoute, Router } from '@angular/router';
import { ReuseTabService } from '@delon/abc/reuse-tab';
import { SettingsService } from '@delon/theme';
import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal';
import { AuthnService } from '../../service/authn.service';
import { SocialsProviderService } from '../../service/socials-provider.service';
import {SocialsProviderBindUserComponent} from "./socials-provider-bind-user/socials-provider-bind-user.component";
import { SocialsProviderBindUserComponent } from './socials-provider-bind-user/socials-provider-bind-user.component';
@Component({
selector: 'app-callback',
@ -52,10 +53,9 @@ export class CallbackComponent implements OnInit {
this.reuseTabService.clear();
// 设置用户Token信息
this.authnService.auth(res.data);
}
else if (res.code === 102) {
} else if (res.code === 102) {
//绑定用户
this.openBindUser(res.message)
this.openBindUser(res.message);
return;
}
this.authnService.navigate({});
@ -70,7 +70,7 @@ export class CallbackComponent implements OnInit {
}
openBindUser(socialUserId: String) {
console.log("bind user : ",this.provider,socialUserId);
console.log('bind user : ', this.provider, socialUserId);
const modal = this.modalService.create({
nzContent: SocialsProviderBindUserComponent,
nzViewContainerRef: this.viewContainerRef,
@ -83,10 +83,7 @@ export class CallbackComponent implements OnInit {
// Return a result when closed
modal.afterClose.subscribe(result => {
if (result.refresh) {
}
});
}
}

View File

@ -14,7 +14,7 @@
<i nz-icon nzType="mobile" nzTheme="outline"></i>
{{ 'mxk.login.tab-mobile' | i18n }}
</label>
<label nz-radio-button nzValue="qrscan" style="width: 50%; text-align: center" (click)="getLoginQrCode()">
<label nz-radio-button nzValue="qrscan" style="width: 50%; text-align: center" (click)="getScanQrCode()">
<i nz-icon nzType="qrcode" nzTheme="outline"></i>{{ 'mxk.login.tab-qrscan' | i18n }}
</label>
</nz-radio-group>
@ -83,9 +83,9 @@
</nz-form-item>
</div>
<div nz-row *ngIf="loginType == 'qrscan'">
<div class="qrcode" id="div_qrcodelogin" style="background: #fff;padding: 20px;"></div>
<div id="qrexpire" *ngIf="qrexpire" style="width: 100%;text-align: center;background: #fff;padding-bottom: 20px;">
二维码过期 <a href="javascript:void(0);" (click)="getLoginQrCode()">刷新</a>
<div class="qrcode" id="div_qrcodelogin" style="background: #fff; padding: 20px"></div>
<div id="qrexpire" *ngIf="qrexpire" style="width: 100%; text-align: center; background: #fff; padding-bottom: 20px">
二维码过期 <a href="javascript:void(0);" (click)="getScanQrCode()">刷新</a>
</div>
</div>
<nz-form-item *ngIf="loginType == 'normal' || loginType == 'mobile'">

View File

@ -309,9 +309,26 @@ export class UserLoginComponent implements OnInit, OnDestroy {
/**
*
*/
getLoginQrCode() {
getScanQrCode() {
this.authnService.clearUser();
console.log(`qrScan : ${this.socials.qrScan}`);
if (this.socials.qrScan === 'workweixin' || this.socials.qrScan === 'dingtalk' || this.socials.qrScan === 'feishu') {
this.socialsProviderService.scanqrcode(this.socials.qrScan).subscribe(res => {
if (res.code === 0) {
if (this.socials.qrScan === 'workweixin') {
this.qrScanWorkweixin(res.data);
} else if (this.socials.qrScan === 'dingtalk') {
this.qrScanDingtalk(res.data);
} else if (this.socials.qrScan === 'feishu') {
this.qrScanFeishu(res.data);
}
}
});
} else {
this.qrexpire = false;
if (this.interval$) {
clearInterval(this.interval$);
}
this.qrCodeService.getLoginQrCode().subscribe(res => {
if (res.code === 0 && res.data.rqCode) {
// 使用返回的 rqCode
@ -326,15 +343,16 @@ export class UserLoginComponent implements OnInit, OnDestroy {
this.qrexpire = true;
this.cdr.detectChanges(); // 更新视图
}, 5 * 60 * 1000); // 5 分钟*/
this.loginByQrCode();
this.scanQrCodeLogin();
}
});
}
}
/**
*
*/
loginByQrCode() {
scanQrCodeLogin() {
const interval = setInterval(() => {
this.qrCodeService
.loginByQrCode({
@ -369,27 +387,6 @@ export class UserLoginComponent implements OnInit, OnDestroy {
}, 5 * 1000); // 5 seconds
}
getQrCode(): void {
this.qrexpire = false;
if (this.interval$) {
clearInterval(this.interval$);
}
this.authnService.clearUser();
this.socialsProviderService.scanqrcode(this.socials.qrScan).subscribe(res => {
if (res.code === 0) {
if (this.socials.qrScan === 'workweixin') {
this.qrScanWorkweixin(res.data);
} else if (this.socials.qrScan === 'dingtalk') {
this.qrScanDingtalk(res.data);
} else if (this.socials.qrScan === 'maxkey') {
this.qrScanMaxkey(res.data);
} else if (this.socials.qrScan === 'feishu') {
this.qrScanFeishu(res.data);
}
}
});
}
// #endregion
ngOnDestroy(): void {

View File

@ -168,8 +168,9 @@
</script>
<!--飞书-->
<!--
<script src="http://sf3-cn.feishucdn.com/obj/static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.1.js"></script>
<script src="http://lf-package-cn.feishucdn.com/obj/feishu-static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.3.js"></script>
<script type="text/javascript">
var fsredirectUri = "";
var QRLoginObj;
@ -190,6 +191,5 @@
window.attachEvent('onmessage', handleMessage);
}
</script>
-->
</html>

View File

@ -107,6 +107,7 @@ public class MaxKeyMvcConfig implements WebMvcConfigurer {
.addPathPatterns("/logout")
.addPathPatterns("/logout/**")
.addPathPatterns("/authz/refused")
.excludePathPatterns("/logon/oauth20/**/**")
.excludePathPatterns("/swagger-ui/**")
.excludePathPatterns("/swagger-resources/**")
.excludePathPatterns("/v3/api-docs/**")