diff --git a/src/main/java/com/newyetai/security/config/SecurityConfiguration.java b/src/main/java/com/newyetai/security/config/SecurityConfiguration.java index e5b70cb..c4bdfd8 100644 --- a/src/main/java/com/newyetai/security/config/SecurityConfiguration.java +++ b/src/main/java/com/newyetai/security/config/SecurityConfiguration.java @@ -1,5 +1,6 @@ package com.newyetai.security.config; +import com.newyetai.security.ucard.UcardAuthenticationProvider; import org.springframework.boot.autoconfigure.AutoConfigurationPackage; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -84,5 +85,11 @@ public class SecurityConfiguration { SsbAuthenticationProvider ssbAuthenticationProvider(UserLoginService userLoginService) { return new SsbAuthenticationProvider(userLoginService); } - + + @Bean + @ConditionalOnBean(UserLoginService.class) + UcardAuthenticationProvider ucardAuthenticationProvider(UserLoginService userLoginService) { + return new UcardAuthenticationProvider(userLoginService); + } + } diff --git a/src/main/java/com/newyetai/security/config/WebSecurityConfigurer.java b/src/main/java/com/newyetai/security/config/WebSecurityConfigurer.java index 373be32..8a68d55 100644 --- a/src/main/java/com/newyetai/security/config/WebSecurityConfigurer.java +++ b/src/main/java/com/newyetai/security/config/WebSecurityConfigurer.java @@ -1,5 +1,7 @@ package com.newyetai.security.config; +import com.newyetai.security.ucard.UcardAuthenticationFilter; +import com.newyetai.security.ucard.UcardAuthenticationProvider; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; @@ -43,7 +45,7 @@ import lombok.extern.slf4j.Slf4j; /** * security配置 - * + * * @author on 2019-11-05 */ @Slf4j @@ -79,6 +81,9 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Autowired private SsbAuthenticationProvider ssbAuthenticationProvider; + @Autowired(required = false) + private UcardAuthenticationProvider ucardAuthenticationProvider; + @Autowired private SwaggerConfig swaggerConfig; @@ -92,9 +97,10 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 添加cas认证提供者 auth.authenticationProvider(upasswordAuthenticationProvider) - .authenticationProvider(mobileAuthenticationProvider) - .authenticationProvider(tokenAuthenticationProvider) - .authenticationProvider(ssbAuthenticationProvider) + .authenticationProvider(mobileAuthenticationProvider) + .authenticationProvider(tokenAuthenticationProvider) + .authenticationProvider(ssbAuthenticationProvider) + .authenticationProvider(ucardAuthenticationProvider); ; } @@ -146,6 +152,8 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { http.addFilterAfter(mobileAuthenticationFilter(), UpasswordAuthenticationFilter.class); http.addFilterAfter(tokenAuthenticationFilter(), UpasswordAuthenticationFilter.class); http.addFilterAfter(ssbAuthenticationFilter(), UpasswordAuthenticationFilter.class); + http.addFilterAfter(ucardAuthenticationFilter(), UpasswordAuthenticationFilter.class); + // 禁用CSRF http.csrf().disable(); @@ -171,14 +179,14 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { } } - + private JwtAuthenticationTokenFilter createJwtAuthenticationTokenFilter() { return new JwtAuthenticationTokenFilter(securityProperties); } /** * 拦截器 - * + * * @return * @throws Exception * @author sr on 2019-11-28 @@ -196,11 +204,11 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { /** * 手机号登录请求过滤器 - * + * * @param authenticationManager * @return - * @author sr on 2020-06-04 * @throws Exception + * @author sr on 2020-06-04 */ private MobileAuthenticationFilter mobileAuthenticationFilter() throws Exception { MobileAuthenticationFilter filter = new MobileAuthenticationFilter(); @@ -216,9 +224,10 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { /** * 账号密码 + * * @return * @throws Exception - * @author sr on 2021-06-22 + * @author sr on 2021-06-22 */ private UpasswordAuthenticationFilter upasswordAuthenticationFilter() throws Exception { UpasswordAuthenticationFilter filter = new UpasswordAuthenticationFilter(); @@ -228,9 +237,10 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { /** * 临时token + * * @return * @throws Exception - * @author sr on 2021-06-22 + * @author sr on 2021-06-22 */ private TokenAuthenticationFilter tokenAuthenticationFilter() throws Exception { TokenAuthenticationFilter filter = new TokenAuthenticationFilter(); @@ -244,4 +254,17 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { return filter; } + /** + * 身份证登录 + * @return + * @throws Exception + * @author sr on 2024-09-23 + */ + private UcardAuthenticationFilter ucardAuthenticationFilter() throws Exception { + UcardAuthenticationFilter filter = new UcardAuthenticationFilter(); + addHandler(filter); + return filter; + } + + } diff --git a/src/main/java/com/newyetai/security/ucard/UcardAuthenticationFilter.java b/src/main/java/com/newyetai/security/ucard/UcardAuthenticationFilter.java new file mode 100644 index 0000000..fac2caf --- /dev/null +++ b/src/main/java/com/newyetai/security/ucard/UcardAuthenticationFilter.java @@ -0,0 +1,60 @@ +package com.newyetai.security.ucard; + +import com.newyetai.usercenter.user.login.dto.LoginUCardDTO; +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +/** + * 账号密码认证过滤器,指定请求组装token,调起认证 + * + * @author sr on 2021-06-21 + */ +public class UcardAuthenticationFilter extends AbstractAuthenticationProcessingFilter { + + private boolean postOnly = true; + + public static final String REQUEST_METHOD = "POST"; + public static final AntPathRequestMatcher requiresAuthenticationRequestMatcher = + new AntPathRequestMatcher("/login_ucard", REQUEST_METHOD); + public static final String LOGIN_REAL_NAME_KEY = "realName"; + public static final String LOGIN_CARD_NO_KEY = "cardNo"; + + public UcardAuthenticationFilter() { + super(requiresAuthenticationRequestMatcher); + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, + HttpServletResponse response) throws AuthenticationException, IOException, ServletException { + + if (postOnly && !REQUEST_METHOD.equals(request.getMethod())) { + throw new AuthenticationServiceException( + "Authentication method not supported: " + request.getMethod()); + } + + String realName = request.getParameter(LOGIN_REAL_NAME_KEY); + String cardNo = request.getParameter(LOGIN_CARD_NO_KEY); + realName = realName == null ? "" : realName.trim(); + cardNo = cardNo == null ? "" : cardNo.trim(); + + AbstractAuthenticationToken authRequest = new UcardAuthenticationToken( + LoginUCardDTO.builder().realName(realName).cardNo(cardNo).build(), cardNo); + + // Allow subclasses to set the "details" property + setDetails(request, authRequest); + + return this.getAuthenticationManager().authenticate(authRequest); + } + + protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) { + authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); + } +} diff --git a/src/main/java/com/newyetai/security/ucard/UcardAuthenticationProvider.java b/src/main/java/com/newyetai/security/ucard/UcardAuthenticationProvider.java new file mode 100644 index 0000000..ba85fb6 --- /dev/null +++ b/src/main/java/com/newyetai/security/ucard/UcardAuthenticationProvider.java @@ -0,0 +1,64 @@ +package com.newyetai.security.ucard; + +import com.newyetai.common.exception.util.Assert; +import com.newyetai.common.validation.util.ValidateUtils; +import com.newyetai.security.dto.SecurityUserDTO; +import com.newyetai.security.expection.BadLoginException; +import com.newyetai.security.mapstruct.UserMapMapper; +import com.newyetai.usercenter.user.login.dto.LoginUCardDTO; +import com.newyetai.usercenter.user.login.dto.UserDetailDTO; +import com.newyetai.usercenter.user.login.service.UserLoginService; +import java.util.HashSet; +import java.util.Set; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +/** + * 账号密码认证provider,比对信息是否匹配 + * + * @author sr on 2021-06-21 + */ +public class UcardAuthenticationProvider implements AuthenticationProvider { + + private UserLoginService userLoginService; + + public UcardAuthenticationProvider(UserLoginService userLoginService) { + this.userLoginService = userLoginService; + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + LoginUCardDTO loginUCardDTO = + (LoginUCardDTO) authentication.getPrincipal(); + String errMsg = ValidateUtils.validate(LoginUCardDTO.class); + Assert.isTrue(errMsg == null, new BadLoginException(errMsg)); + SecurityUserDTO loadedUser = null; + try { + UserDetailDTO userDetailDTO = this.userLoginService.loadUser(loginUCardDTO); + loadedUser = UserMapMapper.INSTANCE.dtoToDto(userDetailDTO); + } catch (BadLoginException be) { + throw be; + } catch (Exception e) { + throw new BadLoginException(e.getMessage(), e); + } + + UcardAuthenticationToken result = + new UcardAuthenticationToken(loadedUser, listUserGrantedAuthorities(loadedUser)); + result.setDetails(authentication.getDetails()); + return result; + } + + @Override + public boolean supports(Class authentication) { + return (UcardAuthenticationToken.class.isAssignableFrom(authentication)); + } + + private Set listUserGrantedAuthorities(UserDetails userDetails) { + // 什么都不用做,访问资源鉴权的时会拿userDetail去缓存获取对应权限 + return new HashSet(); + } + +} diff --git a/src/main/java/com/newyetai/security/ucard/UcardAuthenticationToken.java b/src/main/java/com/newyetai/security/ucard/UcardAuthenticationToken.java new file mode 100644 index 0000000..00eab17 --- /dev/null +++ b/src/main/java/com/newyetai/security/ucard/UcardAuthenticationToken.java @@ -0,0 +1,23 @@ +package com.newyetai.security.ucard; + +import java.util.Collection; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; + + +/** + * 账号密码认证信息 + * @author sr on 2021-06-21 + */ +public class UcardAuthenticationToken extends UsernamePasswordAuthenticationToken { + + public UcardAuthenticationToken(Object principal, Object credentials) { + super(principal, credentials); + } + + public UcardAuthenticationToken(Object principal, Object credentials, + Collection authorities) { + super(principal, credentials, authorities); + } + +} diff --git a/src/main/java/com/newyetai/usercenter/user/dto/UserDetailQueryDTO.java b/src/main/java/com/newyetai/usercenter/user/dto/UserDetailQueryDTO.java index 4e6c701..60a8ebd 100644 --- a/src/main/java/com/newyetai/usercenter/user/dto/UserDetailQueryDTO.java +++ b/src/main/java/com/newyetai/usercenter/user/dto/UserDetailQueryDTO.java @@ -35,5 +35,8 @@ public class UserDetailQueryDTO implements Serializable { private String phone; private Long orgId; - + + /** 身份证号 **/ + private String cardNo; + } diff --git a/src/main/java/com/newyetai/usercenter/user/login/dto/LoginUCardDTO.java b/src/main/java/com/newyetai/usercenter/user/login/dto/LoginUCardDTO.java new file mode 100644 index 0000000..0db2bfe --- /dev/null +++ b/src/main/java/com/newyetai/usercenter/user/login/dto/LoginUCardDTO.java @@ -0,0 +1,29 @@ +package com.newyetai.usercenter.user.login.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import javax.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@Builder +@ApiModel(description = "身份证登录") +public class LoginUCardDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -5406549736684905311L; + + @ApiModelProperty("姓名") + @NotBlank(message = "姓名不能为空") + private String realName; + @ApiModelProperty("身份证号") + @NotBlank(message = "身份证号不能为空") + private String cardNo; + +} diff --git a/src/main/java/com/newyetai/usercenter/user/login/dto/UserDetailDTO.java b/src/main/java/com/newyetai/usercenter/user/login/dto/UserDetailDTO.java index c505361..16080a9 100644 --- a/src/main/java/com/newyetai/usercenter/user/login/dto/UserDetailDTO.java +++ b/src/main/java/com/newyetai/usercenter/user/login/dto/UserDetailDTO.java @@ -9,7 +9,7 @@ import java.util.List; /** * 用户 - * + * * @author sr on 2019-11-05 */ @Builder @@ -24,13 +24,13 @@ public class UserDetailDTO implements Serializable{ @ApiModelProperty("用户id") private Long id; - + @ApiModelProperty("是否超管") private Boolean supeiror ; @ApiModelProperty("类型") private Integer type; - + /** ----------------仅限机构用户--------------- **/ @ApiModelProperty("当前操作机构") private Long orgId; @@ -40,7 +40,7 @@ public class UserDetailDTO implements Serializable{ @ApiModelProperty("当前操作机构类型") private String orgType; - + @ApiModelProperty("是否机构管理员") private Boolean administrator; /** ----------------仅限机构用户--------------- **/ @@ -55,7 +55,7 @@ public class UserDetailDTO implements Serializable{ @ApiModelProperty("是否启用") private Boolean enabled; - + @ApiModelProperty("是否新注册") private Boolean register; @@ -70,7 +70,7 @@ public class UserDetailDTO implements Serializable{ @ApiModelProperty("凭据是否未过期") private Boolean credentialsNonExpired; - + @JsonIgnore @ApiModelProperty("真实姓名") private String realName; @@ -78,10 +78,13 @@ public class UserDetailDTO implements Serializable{ @JsonIgnore @ApiModelProperty("身份证号") private String cardNo; - + @ApiModelProperty("手机号绑定状态") private Boolean phoneBinding; + @ApiModelProperty("是否实名") + private Boolean authenticated ; + @ApiModelProperty("机构列表") @JsonIgnore private List orgs; diff --git a/src/main/java/com/newyetai/usercenter/user/login/service/UserLoginService.java b/src/main/java/com/newyetai/usercenter/user/login/service/UserLoginService.java index e8e6ff4..7398cb3 100644 --- a/src/main/java/com/newyetai/usercenter/user/login/service/UserLoginService.java +++ b/src/main/java/com/newyetai/usercenter/user/login/service/UserLoginService.java @@ -1,5 +1,6 @@ package com.newyetai.usercenter.user.login.service; +import com.newyetai.usercenter.user.login.dto.LoginUCardDTO; import javax.servlet.http.HttpServletRequest; import com.newyetai.security.service.IUserSecurityService; @@ -16,28 +17,30 @@ import com.newyetai.usercenter.user.login.dto.UserDetailDTO; /** * 用户登录 - * @author sr on 2021-06-17 + * @author sr on 2021-06-17 */ public interface UserLoginService extends IUserSecurityService { - + UserDetailDTO loadUser(LoginUsernamePasswordDTO loginUsernamePasswordDTO); - + + UserDetailDTO loadUser(LoginUCardDTO loginUCardDTO); + UserDetailDTO loadUser(LoginPhoneDTO loginPhoneDTO); - + UserDetailDTO loadUser(LoginPhoneToken loginPhoneToken); - + UserDetailDTO loadUser(LoginUserToken loginUserToken); - + UserDetailDTO findUserDetailDTO(UserDetailQueryDTO userDetailQueryDto); - + AuthClientDTO findAuthClientDTO(AuthClientQueryDTO authClientQueryDTO); UserDetailDTO findUserDetailDTO(AuthDetailLoginDTO authDetailDTO); - + /** * 如果需激活请求,判断上下文用户激活状态,如果待激活,查询数据库用户状态,直接拦截 * @return - * @author sr on 2021-06-30 + * @author sr on 2021-06-30 */ void checkActive(HttpServletRequest request); diff --git a/src/main/java/com/newyetai/usercenter/user/login/service/impl/UserLoginServiceImpl.java b/src/main/java/com/newyetai/usercenter/user/login/service/impl/UserLoginServiceImpl.java index c25d564..fcdf71b 100644 --- a/src/main/java/com/newyetai/usercenter/user/login/service/impl/UserLoginServiceImpl.java +++ b/src/main/java/com/newyetai/usercenter/user/login/service/impl/UserLoginServiceImpl.java @@ -1,5 +1,8 @@ package com.newyetai.usercenter.user.login.service.impl; +import com.newyetai.usercenter.user.dto.SuperRealNameTwoAuthDTO; +import com.newyetai.usercenter.user.login.dto.LoginUCardDTO; +import com.newyetai.usercenter.user.service.UserRealNameTwoVerificationService; import java.util.List; import java.util.stream.Collectors; @@ -97,6 +100,9 @@ public class UserLoginServiceImpl implements UserLoginService { @Autowired private SsbInvoker ssbInvoker; + @Autowired + private UserRealNameTwoVerificationService userRealNameTwoVerificationService; + @Override public UserDetailDTO loadUser(LoginUsernamePasswordDTO loginUsernamePasswordDTO) { // 校验参数 @@ -448,4 +454,35 @@ public class UserLoginServiceImpl implements UserLoginService { } + @Override + public UserDetailDTO loadUser(LoginUCardDTO loginUCardDTO) { + String cardNo = loginUCardDTO.getCardNo(); + String realName = loginUCardDTO.getRealName(); + // 查询用户 + List userDetailDTOs = userMapper.listUserDetailDTO(UserDetailQueryDTO.builder() + .cardNo(cardNo).userType(UserTypeEnum.PERSON.getType()).build()); + Assert.isTrue(userDetailDTOs.size() < 2, new BadLoginException("用户数据异常,请联系管理员!")); + if (userDetailDTOs.size() == 1) { + UserDetailDTO userDetailDTO = userDetailDTOs.get(0); + if (userDetailDTO.getAuthenticated()) { + Assert.isTrue(realName.equals(userDetailDTO.getRealName()), + new BadLoginException("用户实名信息错误")); + return userDetailDTO; + } + } + // 未实名,调第三方实名校验 + Long userId = null; + try { + userId = userRealNameTwoVerificationService + .superAuth(SuperRealNameTwoAuthDTO.builder().realName(realName).cardNo(cardNo).build()); + } catch (Exception e) { + throw new BadLoginException(e.getMessage(), e); + } + UserDetailDTO userDetailDTO = this.findUserDetailDTO( + UserDetailQueryDTO.builder().userId(userId).userType(UserTypeEnum.PERSON.getType()) + .build()); + dealActiveStatus(userDetailDTO); + return userDetailDTO; + } + } diff --git a/src/main/java/com/newyetai/usercenter/user/mapper/UserMapper.xml b/src/main/java/com/newyetai/usercenter/user/mapper/UserMapper.xml index b6e8e8a..75089d2 100644 --- a/src/main/java/com/newyetai/usercenter/user/mapper/UserMapper.xml +++ b/src/main/java/com/newyetai/usercenter/user/mapper/UserMapper.xml @@ -107,7 +107,7 @@ and deleted = 0 and status != 3 and (password is null or password = '') - +