ucard login

This commit is contained in:
ran.shang
2025-08-12 10:41:06 +08:00
parent 4526fc1cf8
commit bf59ce0a10
11 changed files with 290 additions and 35 deletions

View File

@@ -1,5 +1,6 @@
package com.newyetai.security.config; package com.newyetai.security.config;
import com.newyetai.security.ucard.UcardAuthenticationProvider;
import org.springframework.boot.autoconfigure.AutoConfigurationPackage; import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -85,4 +86,10 @@ public class SecurityConfiguration {
return new SsbAuthenticationProvider(userLoginService); return new SsbAuthenticationProvider(userLoginService);
} }
@Bean
@ConditionalOnBean(UserLoginService.class)
UcardAuthenticationProvider ucardAuthenticationProvider(UserLoginService userLoginService) {
return new UcardAuthenticationProvider(userLoginService);
}
} }

View File

@@ -1,5 +1,7 @@
package com.newyetai.security.config; 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.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -79,6 +81,9 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired @Autowired
private SsbAuthenticationProvider ssbAuthenticationProvider; private SsbAuthenticationProvider ssbAuthenticationProvider;
@Autowired(required = false)
private UcardAuthenticationProvider ucardAuthenticationProvider;
@Autowired @Autowired
private SwaggerConfig swaggerConfig; private SwaggerConfig swaggerConfig;
@@ -92,9 +97,10 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception { protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 添加cas认证提供者 // 添加cas认证提供者
auth.authenticationProvider(upasswordAuthenticationProvider) auth.authenticationProvider(upasswordAuthenticationProvider)
.authenticationProvider(mobileAuthenticationProvider) .authenticationProvider(mobileAuthenticationProvider)
.authenticationProvider(tokenAuthenticationProvider) .authenticationProvider(tokenAuthenticationProvider)
.authenticationProvider(ssbAuthenticationProvider) .authenticationProvider(ssbAuthenticationProvider)
.authenticationProvider(ucardAuthenticationProvider);
; ;
} }
@@ -146,6 +152,8 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
http.addFilterAfter(mobileAuthenticationFilter(), UpasswordAuthenticationFilter.class); http.addFilterAfter(mobileAuthenticationFilter(), UpasswordAuthenticationFilter.class);
http.addFilterAfter(tokenAuthenticationFilter(), UpasswordAuthenticationFilter.class); http.addFilterAfter(tokenAuthenticationFilter(), UpasswordAuthenticationFilter.class);
http.addFilterAfter(ssbAuthenticationFilter(), UpasswordAuthenticationFilter.class); http.addFilterAfter(ssbAuthenticationFilter(), UpasswordAuthenticationFilter.class);
http.addFilterAfter(ucardAuthenticationFilter(), UpasswordAuthenticationFilter.class);
// 禁用CSRF // 禁用CSRF
http.csrf().disable(); http.csrf().disable();
@@ -199,8 +207,8 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
* *
* @param authenticationManager * @param authenticationManager
* @return * @return
* @author sr on 2020-06-04
* @throws Exception * @throws Exception
* @author sr on 2020-06-04
*/ */
private MobileAuthenticationFilter mobileAuthenticationFilter() throws Exception { private MobileAuthenticationFilter mobileAuthenticationFilter() throws Exception {
MobileAuthenticationFilter filter = new MobileAuthenticationFilter(); MobileAuthenticationFilter filter = new MobileAuthenticationFilter();
@@ -216,6 +224,7 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
/** /**
* 账号密码 * 账号密码
*
* @return * @return
* @throws Exception * @throws Exception
* @author sr on 2021-06-22 * @author sr on 2021-06-22
@@ -228,6 +237,7 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
/** /**
* 临时token * 临时token
*
* @return * @return
* @throws Exception * @throws Exception
* @author sr on 2021-06-22 * @author sr on 2021-06-22
@@ -244,4 +254,17 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
return filter; return filter;
} }
/**
* 身份证登录
* @return
* @throws Exception
* @author sr on 2024-09-23
*/
private UcardAuthenticationFilter ucardAuthenticationFilter() throws Exception {
UcardAuthenticationFilter filter = new UcardAuthenticationFilter();
addHandler(filter);
return filter;
}
} }

View File

@@ -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));
}
}

View File

@@ -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<GrantedAuthority> listUserGrantedAuthorities(UserDetails userDetails) {
// 什么都不用做,访问资源鉴权的时会拿userDetail去缓存获取对应权限
return new HashSet<GrantedAuthority>();
}
}

View File

@@ -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<? extends GrantedAuthority> authorities) {
super(principal, credentials, authorities);
}
}

View File

@@ -36,4 +36,7 @@ public class UserDetailQueryDTO implements Serializable {
private Long orgId; private Long orgId;
/** 身份证号 **/
private String cardNo;
} }

View File

@@ -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;
}

View File

@@ -82,6 +82,9 @@ public class UserDetailDTO implements Serializable{
@ApiModelProperty("手机号绑定状态") @ApiModelProperty("手机号绑定状态")
private Boolean phoneBinding; private Boolean phoneBinding;
@ApiModelProperty("是否实名")
private Boolean authenticated ;
@ApiModelProperty("机构列表") @ApiModelProperty("机构列表")
@JsonIgnore @JsonIgnore
private List<OrgDetailDTO> orgs; private List<OrgDetailDTO> orgs;

View File

@@ -1,5 +1,6 @@
package com.newyetai.usercenter.user.login.service; package com.newyetai.usercenter.user.login.service;
import com.newyetai.usercenter.user.login.dto.LoginUCardDTO;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import com.newyetai.security.service.IUserSecurityService; import com.newyetai.security.service.IUserSecurityService;
@@ -22,6 +23,8 @@ public interface UserLoginService extends IUserSecurityService {
UserDetailDTO loadUser(LoginUsernamePasswordDTO loginUsernamePasswordDTO); UserDetailDTO loadUser(LoginUsernamePasswordDTO loginUsernamePasswordDTO);
UserDetailDTO loadUser(LoginUCardDTO loginUCardDTO);
UserDetailDTO loadUser(LoginPhoneDTO loginPhoneDTO); UserDetailDTO loadUser(LoginPhoneDTO loginPhoneDTO);
UserDetailDTO loadUser(LoginPhoneToken loginPhoneToken); UserDetailDTO loadUser(LoginPhoneToken loginPhoneToken);

View File

@@ -1,5 +1,8 @@
package com.newyetai.usercenter.user.login.service.impl; 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.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -97,6 +100,9 @@ public class UserLoginServiceImpl implements UserLoginService {
@Autowired @Autowired
private SsbInvoker ssbInvoker; private SsbInvoker ssbInvoker;
@Autowired
private UserRealNameTwoVerificationService userRealNameTwoVerificationService;
@Override @Override
public UserDetailDTO loadUser(LoginUsernamePasswordDTO loginUsernamePasswordDTO) { 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<UserDetailDTO> 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;
}
} }

View File

@@ -119,6 +119,9 @@
<if test="param.username!=null and param.username!=''"> <if test="param.username!=null and param.username!=''">
and u.username = #{param.username} and u.username = #{param.username}
</if> </if>
<if test="param.cardNo!=null and param.cardNo!=''">
and u.card_no = #{param.cardNo}
</if>
<if test="param.phone!=null and param.phone!=''"> <if test="param.phone!=null and param.phone!=''">
and u.phone = #{param.phone} and u.phone = #{param.phone}
<if test="param.userType == 2"> <if test="param.userType == 2">