mirror of
https://gitee.com/dromara/MaxKey.git
synced 2025-12-07 01:18:27 +08:00
commit
70cbabde4e
@ -4,4 +4,5 @@ dependencies {
|
|||||||
//local jars
|
//local jars
|
||||||
implementation fileTree(dir: '../maxkey-lib/', include: '*/*.jar')
|
implementation fileTree(dir: '../maxkey-lib/', include: '*/*.jar')
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ public class RQCodeUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BufferedImage write2BufferedImage(String rqCodeText,String format,int width, int height ){
|
public static BufferedImage write2BufferedImage(String rqCodeText,String format,int width, int height){
|
||||||
try {
|
try {
|
||||||
BitMatrix byteMatrix=genRQCode(rqCodeText,width,height);
|
BitMatrix byteMatrix=genRQCode(rqCodeText,width,height);
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ public class RQCodeUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static BitMatrix genRQCode(String rqCodeText,int width, int height ){
|
public static BitMatrix genRQCode(String rqCodeText,int width, int height){
|
||||||
if(width==0){
|
if(width==0){
|
||||||
width=200;
|
width=200;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -95,7 +95,7 @@ public class RedisConnectionFactory {
|
|||||||
timeOut = DEFAULT_CONFIG.DEFAULT_TIMEOUT;
|
timeOut = DEFAULT_CONFIG.DEFAULT_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.password == null || this.password.equals("") || this.password.equalsIgnoreCase("password")) {
|
if (this.password == null || this.password.equals("")) {
|
||||||
this.password = null;
|
this.password = null;
|
||||||
}
|
}
|
||||||
jedisPool = new JedisPool(poolConfig, hostName, port, timeOut, password);
|
jedisPool = new JedisPool(poolConfig, hostName, port, timeOut, password);
|
||||||
|
|||||||
@ -23,13 +23,13 @@ import java.util.List;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.dromara.maxkey.entity.Institutions;
|
import org.dromara.maxkey.entity.Institutions;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.RowMapper;
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
|
||||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
|
||||||
import com.github.benmanes.caffeine.cache.Cache;
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ public class InstitutionsRepository {
|
|||||||
List<Institutions> institutions =
|
List<Institutions> institutions =
|
||||||
jdbcTemplate.query(SELECT_STATEMENT,new InstitutionsRowMapper(),instIdOrDomain,instIdOrDomain,instIdOrDomain);
|
jdbcTemplate.query(SELECT_STATEMENT,new InstitutionsRowMapper(),instIdOrDomain,instIdOrDomain,instIdOrDomain);
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(institutions)) {
|
if (ObjectUtils.isNotEmpty(institutions)) {
|
||||||
inst = institutions.get(0);
|
inst = institutions.get(0);
|
||||||
}
|
}
|
||||||
if(inst != null ) {
|
if(inst != null ) {
|
||||||
|
|||||||
@ -24,13 +24,12 @@ import java.util.ArrayList;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.dromara.maxkey.constants.ConstsRoles;
|
import org.dromara.maxkey.constants.ConstsRoles;
|
||||||
import org.dromara.maxkey.constants.ConstsStatus;
|
import org.dromara.maxkey.constants.ConstsStatus;
|
||||||
import org.dromara.maxkey.entity.idm.Groups;
|
import org.dromara.maxkey.entity.idm.Groups;
|
||||||
import org.dromara.maxkey.entity.idm.UserInfo;
|
import org.dromara.maxkey.entity.idm.UserInfo;
|
||||||
import org.dromara.maxkey.util.StrUtils;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
@ -89,7 +88,7 @@ public class LoginRepository {
|
|||||||
listUserInfo = findByUsernameOrMobileOrEmail(username,password);
|
listUserInfo = findByUsernameOrMobileOrEmail(username,password);
|
||||||
}
|
}
|
||||||
_logger.debug("load UserInfo : {}" , listUserInfo);
|
_logger.debug("load UserInfo : {}" , listUserInfo);
|
||||||
return (CollectionUtils.isNotEmpty(listUserInfo))? listUserInfo.get(0) : null;
|
return (ObjectUtils.isNotEmpty(listUserInfo))? listUserInfo.get(0) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UserInfo> findByUsername(String username, String password) {
|
public List<UserInfo> findByUsername(String username, String password) {
|
||||||
|
|||||||
@ -0,0 +1,63 @@
|
|||||||
|
package org.dromara.maxkey.persistence.service;
|
||||||
|
|
||||||
|
import org.dromara.maxkey.persistence.cache.MomentaryService;
|
||||||
|
import org.dromara.maxkey.util.IdGenerator;
|
||||||
|
import org.dromara.maxkey.util.ObjectTransformer;
|
||||||
|
import org.dromara.mybatis.jpa.id.IdentifierGenerator;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description:
|
||||||
|
* @author: orangeBabu
|
||||||
|
* @time: 15/8/2024 AM9:49
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public class ScanCodeService {
|
||||||
|
private static final Logger _logger = LoggerFactory.getLogger(ScanCodeService.class);
|
||||||
|
|
||||||
|
static final String SCANCODE_TICKET = "login:scancode:%s";
|
||||||
|
|
||||||
|
static final String SCANCODE_CONFIRM = "login:scancode:confirm:%s";
|
||||||
|
|
||||||
|
public static class STATE{
|
||||||
|
public static final String SCANED = "scaned";
|
||||||
|
public static final String CONFIRMED = "confirmed";
|
||||||
|
public static final String CANCELED = "canceled";
|
||||||
|
|
||||||
|
public static final String CANCEL = "cancel";
|
||||||
|
public static final String CONFIRM = "confirm";
|
||||||
|
}
|
||||||
|
|
||||||
|
int validitySeconds = 60 * 3; //default 3 minutes.
|
||||||
|
|
||||||
|
int cancelValiditySeconds = 60 * 1; //default 1 minutes.
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
IdGenerator idGenerator;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MomentaryService momentaryService;
|
||||||
|
|
||||||
|
private String getKey(Long ticket) {
|
||||||
|
return SCANCODE_TICKET.formatted(ticket);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getConfirmKey(Long sessionId) {
|
||||||
|
return SCANCODE_CONFIRM.formatted(sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long createTicket() {
|
||||||
|
Long ticket = 0L;
|
||||||
|
ticket = Long.parseLong(idGenerator.generate());
|
||||||
|
momentaryService.put(getKey(ticket), "ORCode", Duration.ofSeconds(validitySeconds));
|
||||||
|
_logger.info("Ticket {} , Duration {}", ticket , Duration.ofSeconds(validitySeconds));
|
||||||
|
return ticket;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -127,6 +127,7 @@
|
|||||||
},
|
},
|
||||||
"defaultProject": "ng-alain",
|
"defaultProject": "ng-alain",
|
||||||
"cli": {
|
"cli": {
|
||||||
|
"analytics": false,
|
||||||
"packageManager": "yarn"
|
"packageManager": "yarn"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
<i nz-icon nzType="mobile" nzTheme="outline"></i>
|
<i nz-icon nzType="mobile" nzTheme="outline"></i>
|
||||||
{{ 'mxk.login.tab-mobile' | i18n }}
|
{{ 'mxk.login.tab-mobile' | i18n }}
|
||||||
</label>
|
</label>
|
||||||
<label nz-radio-button nzValue="qrscan" style="width: 50%; text-align: center" (click)="getQrCode()">
|
<label nz-radio-button nzValue="qrscan" style="width: 50%; text-align: center" (click)="getLoginQrCode()">
|
||||||
<i nz-icon nzType="qrcode" nzTheme="outline"></i>{{ 'mxk.login.tab-qrscan' | i18n }}
|
<i nz-icon nzType="qrcode" nzTheme="outline"></i>{{ 'mxk.login.tab-qrscan' | i18n }}
|
||||||
</label>
|
</label>
|
||||||
</nz-radio-group>
|
</nz-radio-group>
|
||||||
@ -85,7 +85,7 @@
|
|||||||
<div nz-row *ngIf="loginType=='qrscan'">
|
<div nz-row *ngIf="loginType=='qrscan'">
|
||||||
<div class="qrcode" id="div_qrcodelogin" style="background: #fff;padding: 20px;"> </div>
|
<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;">
|
<div id="qrexpire" *ngIf="qrexpire" style="width: 100%;text-align: center;background: #fff;padding-bottom: 20px;">
|
||||||
二维码过期 <a href="javascript:" (click)="getQrCode()">刷新</a>
|
二维码过期 <a href="javascript:" (click)="getLoginQrCode()">刷新</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<nz-form-item *ngIf="loginType == 'normal' || loginType == 'mobile'">
|
<nz-form-item *ngIf="loginType == 'normal' || loginType == 'mobile'">
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import { finalize } from 'rxjs/operators';
|
|||||||
import { AuthnService } from '../../../service/authn.service';
|
import { AuthnService } from '../../../service/authn.service';
|
||||||
import { ImageCaptchaService } from '../../../service/image-captcha.service';
|
import { ImageCaptchaService } from '../../../service/image-captcha.service';
|
||||||
import { SocialsProviderService } from '../../../service/socials-provider.service';
|
import { SocialsProviderService } from '../../../service/socials-provider.service';
|
||||||
|
import {QrCodeService} from "../../../service/QrCode.service";
|
||||||
import { CONSTS } from '../../../shared/consts';
|
import { CONSTS } from '../../../shared/consts';
|
||||||
|
|
||||||
import { stringify } from 'querystring';
|
import { stringify } from 'querystring';
|
||||||
@ -68,6 +69,7 @@ export class UserLoginComponent implements OnInit, OnDestroy {
|
|||||||
private authnService: AuthnService,
|
private authnService: AuthnService,
|
||||||
private socialsProviderService: SocialsProviderService,
|
private socialsProviderService: SocialsProviderService,
|
||||||
private imageCaptchaService: ImageCaptchaService,
|
private imageCaptchaService: ImageCaptchaService,
|
||||||
|
private qrCodeService: QrCodeService,
|
||||||
@Optional()
|
@Optional()
|
||||||
@Inject(ReuseTabService)
|
@Inject(ReuseTabService)
|
||||||
private reuseTabService: ReuseTabService,
|
private reuseTabService: ReuseTabService,
|
||||||
@ -296,6 +298,14 @@ export class UserLoginComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLoginQrCode() {
|
||||||
|
this.qrCodeService.getLoginQrCode().subscribe(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
getQrCode(): void {
|
getQrCode(): void {
|
||||||
this.qrexpire = false;
|
this.qrexpire = false;
|
||||||
if (this.interval$) {
|
if (this.interval$) {
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { SettingsService, _HttpClient, User } from '@delon/theme';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class QrCodeService {
|
||||||
|
constructor(private http: _HttpClient) {}
|
||||||
|
|
||||||
|
getLoginQrCode() {
|
||||||
|
return this.http.get('/login/genScanCode');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.dromara.maxkey.web.contorller;
|
package org.dromara.maxkey.web.contorller;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -28,14 +29,19 @@ import org.dromara.maxkey.authn.support.kerberos.KerberosService;
|
|||||||
import org.dromara.maxkey.authn.support.rememberme.AbstractRemeberMeManager;
|
import org.dromara.maxkey.authn.support.rememberme.AbstractRemeberMeManager;
|
||||||
import org.dromara.maxkey.authn.support.rememberme.RemeberMe;
|
import org.dromara.maxkey.authn.support.rememberme.RemeberMe;
|
||||||
import org.dromara.maxkey.authn.support.socialsignon.service.SocialSignOnProviderService;
|
import org.dromara.maxkey.authn.support.socialsignon.service.SocialSignOnProviderService;
|
||||||
|
import org.dromara.maxkey.authn.web.AuthorizationUtils;
|
||||||
import org.dromara.maxkey.configuration.ApplicationConfig;
|
import org.dromara.maxkey.configuration.ApplicationConfig;
|
||||||
import org.dromara.maxkey.constants.ConstsLoginType;
|
import org.dromara.maxkey.constants.ConstsLoginType;
|
||||||
|
import org.dromara.maxkey.crypto.Base64Utils;
|
||||||
|
import org.dromara.maxkey.crypto.password.PasswordReciprocal;
|
||||||
import org.dromara.maxkey.entity.*;
|
import org.dromara.maxkey.entity.*;
|
||||||
import org.dromara.maxkey.entity.idm.UserInfo;
|
import org.dromara.maxkey.entity.idm.UserInfo;
|
||||||
import org.dromara.maxkey.password.onetimepwd.AbstractOtpAuthn;
|
import org.dromara.maxkey.password.onetimepwd.AbstractOtpAuthn;
|
||||||
import org.dromara.maxkey.password.sms.SmsOtpAuthnService;
|
import org.dromara.maxkey.password.sms.SmsOtpAuthnService;
|
||||||
|
import org.dromara.maxkey.persistence.service.ScanCodeService;
|
||||||
import org.dromara.maxkey.persistence.service.SocialsAssociatesService;
|
import org.dromara.maxkey.persistence.service.SocialsAssociatesService;
|
||||||
import org.dromara.maxkey.persistence.service.UserInfoService;
|
import org.dromara.maxkey.persistence.service.UserInfoService;
|
||||||
|
import org.dromara.maxkey.util.RQCodeUtils;
|
||||||
import org.dromara.maxkey.web.WebConstants;
|
import org.dromara.maxkey.web.WebConstants;
|
||||||
import org.dromara.maxkey.web.WebContext;
|
import org.dromara.maxkey.web.WebContext;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -56,6 +62,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import static org.reflections.Reflections.log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Crystal.Sea
|
* @author Crystal.Sea
|
||||||
*
|
*
|
||||||
@ -93,7 +101,8 @@ public class LoginEntryPoint {
|
|||||||
@Autowired
|
@Autowired
|
||||||
SmsOtpAuthnService smsAuthnService;
|
SmsOtpAuthnService smsAuthnService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ScanCodeService scanCodeService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
AbstractRemeberMeManager remeberMeManager;
|
AbstractRemeberMeManager remeberMeManager;
|
||||||
@ -259,4 +268,20 @@ public class LoginEntryPoint {
|
|||||||
return new Message<>(Message.FAIL);
|
return new Message<>(Message.FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "生成登录扫描二维码", description = "生成登录扫描二维码", method = "GET")
|
||||||
|
@GetMapping("/genScanCode")
|
||||||
|
public Message<HashMap<String,String>> genScanCode() {
|
||||||
|
log.debug("/genScanCode.");
|
||||||
|
UserInfo userInfo = AuthorizationUtils.getUserInfo();
|
||||||
|
Long ticket = scanCodeService.createTicket();
|
||||||
|
String ticketString = userInfo == null ? ticket.toString() : ticket+","+userInfo.getId();
|
||||||
|
log.debug("ticket string {}",ticketString);
|
||||||
|
String encodeTicket = PasswordReciprocal.getInstance().encode(ticketString);
|
||||||
|
BufferedImage bufferedImage = RQCodeUtils.write2BufferedImage(encodeTicket, "gif", 300, 300);
|
||||||
|
String rqCode = Base64Utils.encodeImage(bufferedImage);
|
||||||
|
HashMap<String,String> codeMap = new HashMap<>();
|
||||||
|
codeMap.put("rqCode", rqCode);
|
||||||
|
codeMap.put("ticket", encodeTicket);
|
||||||
|
return new Message<>(Message.SUCCESS, codeMap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user