diff --git a/maxkey-common/build.gradle b/maxkey-common/build.gradle index cae00db64..531a2f3dd 100644 --- a/maxkey-common/build.gradle +++ b/maxkey-common/build.gradle @@ -3,5 +3,6 @@ description = "maxkey-common" dependencies { //local jars implementation fileTree(dir: '../maxkey-lib/', include: '*/*.jar') - -} \ No newline at end of file + + +} diff --git a/maxkey-common/src/main/java/org/dromara/maxkey/util/RQCodeUtils.java b/maxkey-common/src/main/java/org/dromara/maxkey/util/RQCodeUtils.java index bf92e250f..9122399aa 100644 --- a/maxkey-common/src/main/java/org/dromara/maxkey/util/RQCodeUtils.java +++ b/maxkey-common/src/main/java/org/dromara/maxkey/util/RQCodeUtils.java @@ -1,19 +1,19 @@ /* * Copyright [2020] [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. */ - + package org.dromara.maxkey.util; @@ -27,58 +27,58 @@ import com.google.zxing.common.BitMatrix; public class RQCodeUtils { - + public static void write2File(String path,String rqCodeText,String format,int width, int height ){ - try { + try { BitMatrix byteMatrix=genRQCode(rqCodeText,width,height); - - File file = new File(path); - - QRCode.writeToPath(byteMatrix, format, file); - } catch (Exception e) { - e.printStackTrace(); - } + + File file = new File(path); + + QRCode.writeToPath(byteMatrix, format, file); + } catch (Exception e) { + e.printStackTrace(); + } } - - public static BufferedImage write2BufferedImage(String rqCodeText,String format,int width, int height ){ - try { - BitMatrix byteMatrix=genRQCode(rqCodeText,width,height); - - return QRCode.toBufferedImage(byteMatrix); - } catch (Exception e) { - e.printStackTrace(); - } + + public static BufferedImage write2BufferedImage(String rqCodeText,String format,int width, int height){ + try { + BitMatrix byteMatrix=genRQCode(rqCodeText,width,height); + + return QRCode.toBufferedImage(byteMatrix); + } catch (Exception e) { + e.printStackTrace(); + } return null; } - + public static void write2OutputStream(OutputStream stream,String rqCodeText,String format,int width, int height ){ - try { + try { BitMatrix byteMatrix=genRQCode(rqCodeText,width,height); - - QRCode.writeToStream(byteMatrix, format, stream); - } catch (Exception e) { - e.printStackTrace(); - } + + QRCode.writeToStream(byteMatrix, format, stream); + } catch (Exception e) { + e.printStackTrace(); + } } - - - public static BitMatrix genRQCode(String rqCodeText,int width, int height ){ + + + public static BitMatrix genRQCode(String rqCodeText,int width, int height){ if(width==0){ width=200; } if(height==0){ height=200; } - try { + try { return new MultiFormatWriter().encode( - rqCodeText, - BarcodeFormat.QR_CODE, - width, - height); - } catch (Exception e) { - e.printStackTrace(); - } + rqCodeText, + BarcodeFormat.QR_CODE, + width, + height); + } catch (Exception e) { + e.printStackTrace(); + } return null; } - + } diff --git a/maxkey-core/src/main/java/org/dromara/maxkey/persistence/redis/RedisConnectionFactory.java b/maxkey-core/src/main/java/org/dromara/maxkey/persistence/redis/RedisConnectionFactory.java index 40ee4af20..7edb93407 100644 --- a/maxkey-core/src/main/java/org/dromara/maxkey/persistence/redis/RedisConnectionFactory.java +++ b/maxkey-core/src/main/java/org/dromara/maxkey/persistence/redis/RedisConnectionFactory.java @@ -1,19 +1,19 @@ /* * Copyright [2020] [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. */ - + package org.dromara.maxkey.persistence.redis; @@ -26,7 +26,7 @@ import redis.clients.jedis.JedisPoolConfig; public class RedisConnectionFactory { private static final Logger _logger = LoggerFactory.getLogger(RedisConnectionFactory.class); - + public static class DEFAULT_CONFIG { /** * Redis默认服务器IP @@ -95,7 +95,7 @@ public class RedisConnectionFactory { 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; } jedisPool = new JedisPool(poolConfig, hostName, port, timeOut, password); @@ -120,7 +120,7 @@ public class RedisConnectionFactory { Jedis jedis = jedisPool.getResource(); _logger.trace("return jedisPool Resource ."); return jedis; - + } public void close(Jedis conn) { @@ -130,7 +130,7 @@ public class RedisConnectionFactory { _logger.trace("closed conn ."); } - + public String getHostName() { return hostName; } @@ -170,5 +170,5 @@ public class RedisConnectionFactory { public JedisPoolConfig getPoolConfig() { return poolConfig; } - + } diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/InstitutionsRepository.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/InstitutionsRepository.java index 6f9fdec27..8526c7056 100644 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/InstitutionsRepository.java +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/InstitutionsRepository.java @@ -1,19 +1,19 @@ /* * 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. */ - + package org.dromara.maxkey.persistence.repository; @@ -23,38 +23,38 @@ import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.ObjectUtils; import org.dromara.maxkey.entity.Institutions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.JdbcTemplate; 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.Caffeine; public class InstitutionsRepository { static final Logger _logger = LoggerFactory.getLogger(InstitutionsRepository.class); - - private static final String SELECT_STATEMENT = + + private static final String SELECT_STATEMENT = "select * from mxk_institutions where id = ? or domain = ? or consoledomain = ?" ; - + private static final String DEFAULT_INSTID = "1"; - protected static final Cache institutionsStore = + protected static final Cache institutionsStore = Caffeine.newBuilder() .expireAfterWrite(60, TimeUnit.MINUTES) .build(); - + //id domain mapping protected static final ConcurrentHashMap mapper = new ConcurrentHashMap<>(); - + protected JdbcTemplate jdbcTemplate; - + public InstitutionsRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } - + public Institutions get(String instIdOrDomain) { _logger.trace(" instId {}" , instIdOrDomain); Institutions inst = getByInstIdOrDomain(instIdOrDomain); @@ -64,15 +64,15 @@ public class InstitutionsRepository { } return inst; } - + private Institutions getByInstIdOrDomain(String instIdOrDomain) { _logger.trace(" instId {}" , instIdOrDomain); Institutions inst = institutionsStore.getIfPresent(mapper.get(instIdOrDomain)==null ? DEFAULT_INSTID : mapper.get(instIdOrDomain) ); if(inst == null) { - List institutions = + List institutions = jdbcTemplate.query(SELECT_STATEMENT,new InstitutionsRowMapper(),instIdOrDomain,instIdOrDomain,instIdOrDomain); - - if (CollectionUtils.isNotEmpty(institutions)) { + + if (ObjectUtils.isNotEmpty(institutions)) { inst = institutions.get(0); } if(inst != null ) { @@ -81,10 +81,10 @@ public class InstitutionsRepository { mapper.put(inst.getId(), inst.getDomain()); } } - + return inst; } - + public class InstitutionsRowMapper implements RowMapper { @Override public Institutions mapRow(ResultSet rs, int rowNum) throws SQLException { diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/LoginRepository.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/LoginRepository.java index 238b76be2..d5752a9e4 100644 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/LoginRepository.java +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/LoginRepository.java @@ -1,19 +1,19 @@ /* * Copyright [2020] [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. */ - + package org.dromara.maxkey.persistence.repository; @@ -24,13 +24,12 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; -import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.dromara.maxkey.constants.ConstsRoles; import org.dromara.maxkey.constants.ConstsStatus; import org.dromara.maxkey.entity.idm.Groups; import org.dromara.maxkey.entity.idm.UserInfo; -import org.dromara.maxkey.util.StrUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.JdbcTemplate; @@ -57,28 +56,28 @@ public class LoginRepository { private static final String GROUPS_SELECT_STATEMENT = "select distinct g.id,g.groupcode,g.groupname from mxk_userinfo u,mxk_groups g,mxk_group_member gm where u.id = ? and u.id=gm.memberid and gm.groupid=g.id "; private static final String DEFAULT_USERINFO_SELECT_STATEMENT = "select * from mxk_userinfo where username = ? "; - + private static final String DEFAULT_USERINFO_SELECT_STATEMENT_USERNAME_MOBILE = "select * from mxk_userinfo where (username = ? or mobile = ?)"; - + private static final String DEFAULT_USERINFO_SELECT_STATEMENT_USERNAME_MOBILE_EMAIL = "select * from mxk_userinfo where (username = ? or mobile = ? or email = ?) "; - + private static final String DEFAULT_MYAPPS_SELECT_STATEMENT = "select distinct app.id,app.appname from mxk_apps app,mxk_access gp,mxk_groups g where app.id=gp.appid and app.status = 1 and gp.groupid=g.id and g.id in(%s)"; - + protected JdbcTemplate jdbcTemplate; - + /** * 1 (USERNAME) 2 (USERNAME | MOBILE) 3 (USERNAME | MOBILE | EMAIL) */ public static int LOGIN_ATTRIBUTE_TYPE = 2; - + public LoginRepository(){ - + } - + public LoginRepository(JdbcTemplate jdbcTemplate){ this.jdbcTemplate=jdbcTemplate; } - + public UserInfo find(String username, String password) { List listUserInfo = null ; if( LOGIN_ATTRIBUTE_TYPE == 1) { @@ -89,37 +88,37 @@ public class LoginRepository { listUserInfo = findByUsernameOrMobileOrEmail(username,password); } _logger.debug("load UserInfo : {}" , listUserInfo); - return (CollectionUtils.isNotEmpty(listUserInfo))? listUserInfo.get(0) : null; + return (ObjectUtils.isNotEmpty(listUserInfo))? listUserInfo.get(0) : null; } - + public List findByUsername(String username, String password) { return jdbcTemplate.query( - DEFAULT_USERINFO_SELECT_STATEMENT, + DEFAULT_USERINFO_SELECT_STATEMENT, new UserInfoRowMapper(), username ); } - + public List findByUsernameOrMobile(String username, String password) { return jdbcTemplate.query( - DEFAULT_USERINFO_SELECT_STATEMENT_USERNAME_MOBILE, + DEFAULT_USERINFO_SELECT_STATEMENT_USERNAME_MOBILE, new UserInfoRowMapper(), username,username ); } - + public List findByUsernameOrMobileOrEmail(String username, String password) { return jdbcTemplate.query( - DEFAULT_USERINFO_SELECT_STATEMENT_USERNAME_MOBILE_EMAIL, + DEFAULT_USERINFO_SELECT_STATEMENT_USERNAME_MOBILE_EMAIL, new UserInfoRowMapper(), username,username,username ); } - + /** * 閿佸畾鐢ㄦ埛锛歩slock锛�1 鐢ㄦ埛瑙i攣 2 鐢ㄦ埛閿佸畾 - * + * * @param userInfo */ public void updateLock(UserInfo userInfo) { @@ -137,7 +136,7 @@ public class LoginRepository { /** * 閿佸畾鐢ㄦ埛锛歩slock锛�1 鐢ㄦ埛瑙i攣 2 鐢ㄦ埛閿佸畾 - * + * * @param userInfo */ public void updateUnlock(UserInfo userInfo) { @@ -155,7 +154,7 @@ public class LoginRepository { /** * reset BadPasswordCount And Lockout - * + * * @param userInfo */ public void updateLockout(UserInfo userInfo) { @@ -173,7 +172,7 @@ public class LoginRepository { /** * if login password is error ,BadPasswordCount++ and set bad date - * + * * @param userInfo */ public void updateBadPasswordCount(UserInfo userInfo) { @@ -190,15 +189,15 @@ public class LoginRepository { _logger.error(e.getMessage()); } } - + public List queryAuthorizedApps(List grantedAuthoritys) { String grantedAuthorityString="'ROLE_ALL_USER'"; for(GrantedAuthority grantedAuthority : grantedAuthoritys) { grantedAuthorityString += ",'"+ grantedAuthority.getAuthority()+"'"; } - + ArrayList listAuthorizedApps = (ArrayList) jdbcTemplate.query( - String.format(DEFAULT_MYAPPS_SELECT_STATEMENT, grantedAuthorityString), + String.format(DEFAULT_MYAPPS_SELECT_STATEMENT, grantedAuthorityString), new RowMapper() { public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException { return new SimpleGrantedAuthority(rs.getString("id")); @@ -208,7 +207,7 @@ public class LoginRepository { _logger.debug("list Authorized Apps {}" , listAuthorizedApps); return listAuthorizedApps; } - + public List queryGroups(UserInfo userInfo) { List listRoles = jdbcTemplate.query(GROUPS_SELECT_STATEMENT, new RowMapper() { public Groups mapRow(ResultSet rs, int rowNum) throws SQLException { @@ -222,7 +221,7 @@ public class LoginRepository { /** * grant Authority by userinfo - * + * * @param userInfo * @return ArrayList */ @@ -237,7 +236,7 @@ public class LoginRepository { grantedAuthority.add(ConstsRoles.ROLE_ORDINARY_USER); for (Groups group : listGroups) { grantedAuthority.add(new SimpleGrantedAuthority(group.getId())); - if(group.getGroupCode().startsWith("ROLE_") + if(group.getGroupCode().startsWith("ROLE_") && !grantedAuthority.contains(new SimpleGrantedAuthority(group.getGroupCode()))) { grantedAuthority.add(new SimpleGrantedAuthority(group.getGroupCode())); } @@ -246,19 +245,19 @@ public class LoginRepository { return grantedAuthority; } - - + + public void updateLastLogin(UserInfo userInfo) { jdbcTemplate.update(LOGIN_USERINFO_UPDATE_STATEMENT, - new Object[] { - userInfo.getLastLoginTime(), - userInfo.getLastLoginIp(), - userInfo.getLoginCount() + 1, - userInfo.getId() + new Object[] { + userInfo.getLastLoginTime(), + userInfo.getLastLoginIp(), + userInfo.getLoginCount() + 1, + userInfo.getId() }, new int[] { Types.TIMESTAMP, Types.VARCHAR, Types.INTEGER, Types.VARCHAR }); } - + public class UserInfoRowMapper implements RowMapper { @Override public UserInfo mapRow(ResultSet rs, int rowNum) throws SQLException { @@ -372,7 +371,7 @@ public class LoginRepository { if (userInfo.getTheme() == null || userInfo.getTheme().equalsIgnoreCase("")) { userInfo.setTheme("default"); } - + return userInfo; } } diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/ScanCodeService.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/ScanCodeService.java new file mode 100644 index 000000000..e0c017888 --- /dev/null +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/ScanCodeService.java @@ -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; + } +} diff --git a/maxkey-web-frontend/maxkey-web-app/angular.json b/maxkey-web-frontend/maxkey-web-app/angular.json index df85f80cf..48d6752fe 100644 --- a/maxkey-web-frontend/maxkey-web-app/angular.json +++ b/maxkey-web-frontend/maxkey-web-app/angular.json @@ -127,6 +127,7 @@ }, "defaultProject": "ng-alain", "cli": { + "analytics": false, "packageManager": "yarn" } } diff --git a/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/login/login.component.html b/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/login/login.component.html index 6ee4d61df..6eea0463e 100644 --- a/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/login/login.component.html +++ b/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/login/login.component.html @@ -14,7 +14,7 @@ {{ 'mxk.login.tab-mobile' | i18n }} -