diff --git a/research-admin/src/main/java/com/research/web/controller/system/SysLoginController.java b/research-admin/src/main/java/com/research/web/controller/system/SysLoginController.java index 1f5edbbb..f29224e0 100644 --- a/research-admin/src/main/java/com/research/web/controller/system/SysLoginController.java +++ b/research-admin/src/main/java/com/research/web/controller/system/SysLoginController.java @@ -3,9 +3,19 @@ package com.research.web.controller.system; import java.util.List; import java.util.Set; +import com.research.common.annotation.Anonymous; +import com.research.common.core.domain.JsonResponse; +import com.research.framework.web.service.WebTmsLoginService; +import com.research.system.domain.dto.SmsDto; +import com.research.system.domain.vo.SmsVo; +import com.research.system.domain.vo.TmsLoginUserVo; import com.research.system.service.SessionService; +import com.research.system.service.TmsLoginService; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import liquibase.pro.packaged.E; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -45,7 +55,10 @@ public class SysLoginController private TokenService tokenService; @Resource private SessionService sessionService; - + @Resource + private WebTmsLoginService tmsTenantUserService; + @Resource + private TmsLoginService dmsLoginService; /** * 登录方法 * @@ -118,4 +131,23 @@ public class SysLoginController List menus = menuService.selectMenuTreeByUserId(userId); return AjaxResult.success(menuService.buildMenus(menus)); } + + + @ApiOperation("获取手机验证码") + @GetMapping("/getSmsCode") + @Anonymous + public JsonResponse getSmsCode(@ApiParam @Validated SmsDto.GetSmsCode dto) { + return JsonResponse.ok(dmsLoginService.sendSmsCode(dto.getPhone())); + } + + @ApiOperation("手机号登录") + @PostMapping("/phoneLogin") + @Anonymous + public AjaxResult loginByPhone(@ApiParam @Validated @RequestBody TmsLoginUserVo.PhoneLogin dto) { + AjaxResult ajax = AjaxResult.success(); + // 生成令牌 + String token = tmsTenantUserService.loginByPhone(dto.getPhone(), dto.getSmsCode()).getToken(); + ajax.put(Constants.TOKEN, token); + return ajax; + } } diff --git a/research-admin/src/main/java/com/research/web/controller/tenant/TmsLoginController.java b/research-admin/src/main/java/com/research/web/controller/tenant/TmsLoginController.java index 09421d6d..82a6daf8 100644 --- a/research-admin/src/main/java/com/research/web/controller/tenant/TmsLoginController.java +++ b/research-admin/src/main/java/com/research/web/controller/tenant/TmsLoginController.java @@ -172,4 +172,12 @@ public class TmsLoginController { public JsonResponse getSmsCode(@ApiParam @Validated SmsDto.GetSmsCode dto) { return JsonResponse.ok(dmsLoginService.sendSmsCode(dto.getPhone())); } + + @ApiOperation("手机号登录") + @PostMapping("/phoneLogin") + @Anonymous + public JsonResponse loginByPhone(@ApiParam @Validated @RequestBody TmsLoginUserVo.PhoneLogin dto) { + // 生成令牌 + return JsonResponse.ok(tmsTenantUserService.loginByPhone(dto.getPhone(), dto.getSmsCode())); + } } diff --git a/research-framework/src/main/java/com/research/framework/config/SecurityConfig.java b/research-framework/src/main/java/com/research/framework/config/SecurityConfig.java index 39d35c2a..ea85dfe5 100644 --- a/research-framework/src/main/java/com/research/framework/config/SecurityConfig.java +++ b/research-framework/src/main/java/com/research/framework/config/SecurityConfig.java @@ -1,5 +1,6 @@ package com.research.framework.config; +import com.research.framework.security.provider.AdminPhoneAuthenticationProvider; import com.research.framework.security.provider.DmsUserAuthenticationProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -76,7 +77,7 @@ public class SecurityConfig DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setUserDetailsService(userDetailsService); daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder()); - return new ProviderManager(daoAuthenticationProvider, dmsUserAuthenticationProvider()); + return new ProviderManager(daoAuthenticationProvider, dmsUserAuthenticationProvider(), adminPhoneAuthenticationProvider()); } /** @@ -143,6 +144,11 @@ public class SecurityConfig return new DmsUserAuthenticationProvider(); } + @Bean + public AdminPhoneAuthenticationProvider adminPhoneAuthenticationProvider(){ + return new AdminPhoneAuthenticationProvider(); + } + // @Override // protected void configure(AuthenticationManagerBuilder auth) throws Exception { // //填报端认证 @@ -155,7 +161,9 @@ public class SecurityConfig public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // ... 其他配置 - .authenticationProvider(dmsUserAuthenticationProvider()); // 注入自定义 Provider + .authenticationProvider(dmsUserAuthenticationProvider()) + .authenticationProvider(adminPhoneAuthenticationProvider()); // 注入自定义 Provider + return http.build(); } } diff --git a/research-framework/src/main/java/com/research/framework/security/provider/AdminPhoneAuthenticationProvider.java b/research-framework/src/main/java/com/research/framework/security/provider/AdminPhoneAuthenticationProvider.java new file mode 100644 index 00000000..edaf85fb --- /dev/null +++ b/research-framework/src/main/java/com/research/framework/security/provider/AdminPhoneAuthenticationProvider.java @@ -0,0 +1,38 @@ +package com.research.framework.security.provider; + +import com.research.framework.security.token.AdminPhoneAuthenticationToken; +import com.research.framework.web.service.UserDetailsServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; + +import javax.annotation.Resource; + +@Slf4j +public class AdminPhoneAuthenticationProvider implements AuthenticationProvider { + + @Resource + private UserDetailsServiceImpl userDetailsService; + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + AdminPhoneAuthenticationToken authenticationToken = (AdminPhoneAuthenticationToken) authentication; + String phone = (String) authentication.getPrincipal(); + String smsCode = (String) authentication.getCredentials(); + //通过openId获取用户 + log.info("通过手机号获取用户:{}", phone); + UserDetails userDetails = userDetailsService.loadUserByPhone(phone); + //返回用户信息 + AdminPhoneAuthenticationToken result = new AdminPhoneAuthenticationToken(userDetails, smsCode, null); + result.setDetails(authentication.getDetails()); + return result; + } + + @Override + public boolean supports(Class authentication) { + return (AdminPhoneAuthenticationToken.class.isAssignableFrom(authentication)); + } + +} diff --git a/research-framework/src/main/java/com/research/framework/security/token/AdminPhoneAuthenticationToken.java b/research-framework/src/main/java/com/research/framework/security/token/AdminPhoneAuthenticationToken.java new file mode 100644 index 00000000..09dad9f1 --- /dev/null +++ b/research-framework/src/main/java/com/research/framework/security/token/AdminPhoneAuthenticationToken.java @@ -0,0 +1,81 @@ +package com.research.framework.security.token; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.SpringSecurityCoreVersion; + +import java.util.Collection; + +/** + * @author zhangsan + * @date 2022-08-11 21:15 + * @description TODO + */ +public class AdminPhoneAuthenticationToken extends AbstractAuthenticationToken { + private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; + + private final Object principal; + private String credentials; +// private final Object detail; + + /** + * 准备登录时调用 + * 此构造函数用来初始化未授信凭据. + * + * @param principal + * @param credentials + */ + public AdminPhoneAuthenticationToken(Object principal, String credentials, Object detail) { + super(null); + this.principal = principal; + this.credentials = credentials; +// this.detail = detail; + setAuthenticated(false); + } + + /** + * 登录成功时调用 + * 此构函数用来初始化已授信凭据. + * @param principal + * @param authorities + */ + public AdminPhoneAuthenticationToken(Object principal, String credentials, Collection authorities) { + super(authorities); + this.principal = principal; + this.credentials = credentials; +// this.detail = null; +// super.setAuthenticated(true); +// super.setAuthenticated(false); + super.setAuthenticated(true); + } + + @Override + public Object getPrincipal() { + return principal; + } + + @Override + public Object getCredentials() { + return credentials; + } + +// @Override +// public Object getDetails() { +// return detail; +// } + + @Override + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { + if (isAuthenticated) { + throw new IllegalArgumentException( + "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); + } + super.setAuthenticated(false); + } + + @Override + public void eraseCredentials() { + super.eraseCredentials(); + credentials = null; + } +} diff --git a/research-framework/src/main/java/com/research/framework/web/service/UserDetailsServiceImpl.java b/research-framework/src/main/java/com/research/framework/web/service/UserDetailsServiceImpl.java index 79439397..6431dcf9 100644 --- a/research-framework/src/main/java/com/research/framework/web/service/UserDetailsServiceImpl.java +++ b/research-framework/src/main/java/com/research/framework/web/service/UserDetailsServiceImpl.java @@ -143,4 +143,37 @@ public class UserDetailsServiceImpl implements UserDetailsService DynamicDataSourceContextHolder.clearDataSourceType(); return new LoginUser(user.getDmsUserId(), user.getHospitalId(), sysUser, menuPermission, user.getTenantId() ,user.getScoreId()); } + + public UserDetails createLoginUser(SysUser user) { + return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user)); + } + + + public UserDetails loadUserByPhone(String phone) { + SysUser user = userService.selectUserByUserName(phone); + if (StringUtils.isNull(user)) + { + log.info("登录用户:{} 不存在.", phone); + throw new ServiceException(MessageUtils.message("user.not.exists")); + } + else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) + { + log.info("登录用户:{} 已被删除.", phone); + throw new ServiceException(MessageUtils.message("user.password.delete")); + } + else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) + { + log.info("登录用户:{} 已被停用.", phone); + throw new ServiceException(MessageUtils.message("user.blocked")); + } + +// passwordService.validate(user); + List prjProjInfos = prjProjInfoMapper.selectByExample(new PrjProjInfoExample()); + Long tenantId = 0L; + if (CollUtil.isNotEmpty(prjProjInfos)) { + tenantId = prjProjInfos.get(0).getTenantId(); + } + return createLoginUser(user, tenantId); + + } } diff --git a/research-framework/src/main/java/com/research/framework/web/service/WebTmsLoginService.java b/research-framework/src/main/java/com/research/framework/web/service/WebTmsLoginService.java index 123c74d6..b6256f52 100644 --- a/research-framework/src/main/java/com/research/framework/web/service/WebTmsLoginService.java +++ b/research-framework/src/main/java/com/research/framework/web/service/WebTmsLoginService.java @@ -3,10 +3,12 @@ package com.research.framework.web.service; import com.research.common.constant.CacheConstants; import com.research.common.constant.Constants; import com.research.common.constant.UserConstants; +import com.research.common.core.domain.PhoneCode; import com.research.common.core.domain.entity.SysUser; import com.research.common.core.domain.model.LoginUser; import com.research.common.core.redis.RedisCache; import com.research.common.exception.ServiceException; +import com.research.common.exception.base.BaseException; import com.research.common.exception.user.*; import com.research.common.utils.DateUtils; import com.research.common.utils.MessageUtils; @@ -15,9 +17,13 @@ import com.research.common.utils.ip.IpUtils; import com.research.framework.manager.AsyncManager; import com.research.framework.manager.factory.AsyncFactory; import com.research.framework.security.context.AuthenticationContextHolder; +import com.research.framework.security.token.AdminPhoneAuthenticationToken; import com.research.framework.security.token.DmsUserAuthenticationToken; +import com.research.system.domain.vo.TmsLoginUserVo; import com.research.system.service.ISysConfigService; import com.research.system.service.ISysUserService; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.formula.constant.ErrorConstant; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -31,6 +37,7 @@ import javax.annotation.Resource; * * @author research */ +@Slf4j @Component public class WebTmsLoginService { @@ -258,6 +265,73 @@ public class WebTmsLoginService } } + private String getPhoneCodeKey(String phone) { + return CacheConstants.PHONE_CODE_KEY + phone; + } + + /** + * 手机号登录 + * + * @param phone 手机号 + * @param smsCode 验证码 + * @param phone + * @return + */ + public TmsLoginUserVo.Result loginByPhone(String phone, String smsCode) { + log.info("phone:{}, {}", phone, smsCode); + + //手机验证码是否正确 + PhoneCode phoneCode = redisCache.getCacheObject(getPhoneCodeKey(phone)); + if (phoneCode == null || !phoneCode.getCode().equals(smsCode)) { + throw new BaseException("验证码错误"); + } + redisCache.deleteObject(getPhoneCodeKey(smsCode)); + + //根据手机号查询用户 + SysUser sysUser = userService.selectUserByPhone(phone); + if (sysUser == null) { + throw new BaseException("手机号未找到"); + } + + Authentication authentication = null; + try { + AdminPhoneAuthenticationToken adminPhoneAuthenticationToken = new AdminPhoneAuthenticationToken(phone, smsCode, null); + AuthenticationContextHolder.setContext(adminPhoneAuthenticationToken); + // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername + authentication = authenticationManager.authenticate(adminPhoneAuthenticationToken); + } catch (Exception e) { + if (e instanceof BadCredentialsException) { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } else { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, e.getMessage())); + throw new ServiceException(e.getMessage()); + } + } finally { + AuthenticationContextHolder.clearContext(); + } + //用户不存在 新增 + if (authentication == null || authentication.getPrincipal() == null) { + log.info("登录失败authentication:{}", authentication); + throw new BaseException("登录失败,请联系系统管理人员"); + } + + Object principal = authentication.getPrincipal(); + log.info("登录手机号:{}", principal); + AsyncManager.me().execute(AsyncFactory.recordLogininfor(sysUser.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + recordLoginInfo(loginUser.getUserId()); + TmsLoginUserVo.Result result = new TmsLoginUserVo.Result(); + // 生成token + result.setToken(tokenService.createToken(loginUser)); + result.setId(loginUser.getUserId()); + if (loginUser.getUser() != null) { + result.setPhone(loginUser.getUser().getPhonenumber()); +// result.setTemp(sysUser.getTemp()); + } + return result; + } + /** * 记录登录信息 * diff --git a/research-system/src/main/java/com/research/system/domain/vo/TmsLoginUserVo.java b/research-system/src/main/java/com/research/system/domain/vo/TmsLoginUserVo.java index 91accfb2..707af3bf 100644 --- a/research-system/src/main/java/com/research/system/domain/vo/TmsLoginUserVo.java +++ b/research-system/src/main/java/com/research/system/domain/vo/TmsLoginUserVo.java @@ -1,9 +1,13 @@ package com.research.system.domain.vo; +import cn.hutool.core.util.StrUtil; import com.research.common.core.domain.entity.SysRole; +import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; import java.util.Date; import java.util.List; @@ -15,6 +19,17 @@ import java.util.List; */ public class TmsLoginUserVo { + @Data + @ApiModel("DTO-小程序登录") + public static class PhoneLogin { + @ApiModelProperty("手机号") + @NotBlank(message = "phone不能为空") + @Pattern(regexp = "(?:0|86|\\+86)?1[3-9]\\d{9}", message = "phone格式不正确") + private String phone; + + @ApiModelProperty("验证码") + private String smsCode; + } @Data public static class Query { @@ -89,4 +104,22 @@ public class TmsLoginUserVo { List roles; } + + @Data + public static class Result{ + private String account; + private String phone; + private String token; + private Long id; + + private Byte temp; + + public String getAccount(){ + if (StrUtil.isBlank(phone)) { + return null; + } + return StrUtil.hide(phone, 3, 7); + + } + } } diff --git a/research-system/src/main/java/com/research/system/mapper/SysUserMapper.java b/research-system/src/main/java/com/research/system/mapper/SysUserMapper.java index 8f7568db..c1cc4a03 100644 --- a/research-system/src/main/java/com/research/system/mapper/SysUserMapper.java +++ b/research-system/src/main/java/com/research/system/mapper/SysUserMapper.java @@ -124,4 +124,12 @@ public interface SysUserMapper * @return 结果 */ public SysUser checkEmailUnique(String email); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByPhone(String phone); } diff --git a/research-system/src/main/java/com/research/system/service/ISysUserService.java b/research-system/src/main/java/com/research/system/service/ISysUserService.java index dceef8d7..fe071fcf 100644 --- a/research-system/src/main/java/com/research/system/service/ISysUserService.java +++ b/research-system/src/main/java/com/research/system/service/ISysUserService.java @@ -203,4 +203,11 @@ public interface ISysUserService * @return 结果 */ public String importUser(List userList, Boolean isUpdateSupport, String operName); + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + public SysUser selectUserByPhone(String phone); } diff --git a/research-system/src/main/java/com/research/system/service/impl/SysUserServiceImpl.java b/research-system/src/main/java/com/research/system/service/impl/SysUserServiceImpl.java index 0dc36271..c2dc33f2 100644 --- a/research-system/src/main/java/com/research/system/service/impl/SysUserServiceImpl.java +++ b/research-system/src/main/java/com/research/system/service/impl/SysUserServiceImpl.java @@ -547,4 +547,9 @@ public class SysUserServiceImpl implements ISysUserService } return successMsg.toString(); } + + @Override + public SysUser selectUserByPhone(String phone) { + return userMapper.selectUserByPhone(phone); + } } diff --git a/research-system/src/main/resources/mapper/dao/KtsGroupDao.xml b/research-system/src/main/resources/mapper/dao/KtsGroupDao.xml index 36099966..c6b7a141 100644 --- a/research-system/src/main/resources/mapper/dao/KtsGroupDao.xml +++ b/research-system/src/main/resources/mapper/dao/KtsGroupDao.xml @@ -207,9 +207,9 @@ select o.id as orgId, o.org_name as orgName, - SUM(CASE WHEN m.qualification = '5' THEN 1 ELSE 0 END) AS ss, - SUM(CASE WHEN m.qualification = '6' THEN 1 ELSE 0 END) AS bs, - SUM(CASE WHEN m.qualification = '7' THEN 1 ELSE 0 END) AS bsh + SUM(CASE WHEN m.reading_status = '0' THEN 1 ELSE 0 END) AS ss, + SUM(CASE WHEN m.reading_status = '1' THEN 1 ELSE 0 END) AS bs, + SUM(CASE WHEN m.reading_status = '2' THEN 1 ELSE 0 END) AS bsh from prj_proj_org o left join kts_kt_group g on g.proj_org_id = o.id and g.del_flag = 0 @@ -327,32 +327,30 @@ - - - - - + + + + + select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1 + + insert into sys_user(