CMM 1 year ago
parent
commit
3989403656
23 changed files with 454 additions and 244 deletions
  1. +1
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/common/handler/GlobalResponseHandler.java
  2. +2
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java
  3. +2
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/AnnualPlanLibManage.java
  4. +22
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/sys/model/enumeration/DataScopeEnum.java
  5. +30
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/constant/LoginTypeEnum.java
  6. +0
    -20
      pmapi/src/main/java/com/ningdatech/pmapi/user/controller/NdUserAuthController.java
  7. +0
    -20
      pmapi/src/main/java/com/ningdatech/pmapi/user/controller/NdUserInfoController.java
  8. +9
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/user/controller/UserAuthController.java
  9. +38
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/manage/UserAuthLoginManage.java
  10. +5
    -8
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/WebSecurityConfig.java
  11. +11
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/constants/UserDeatilsServiceConstant.java
  12. +6
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/AccountIdLoginUserDetailService.java
  13. +108
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthFilter.java
  14. +103
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthProvider.java
  15. +19
    -12
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthSecurityConfig.java
  16. +13
    -5
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthToken.java
  17. +67
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialLoginUserDetailService.java
  18. +0
    -71
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthFilter.java
  19. +0
    -65
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthProvider.java
  20. +5
    -13
      pmapi/src/main/resources/integration/zwdd-dev.yml
  21. +11
    -10
      pmapi/src/main/resources/integration/zwdd-prod.yml
  22. +1
    -1
      pmapi/src/main/resources/security/auth-dev.yml
  23. +1
    -1
      pmapi/src/main/resources/security/auth-prod.yml

+ 1
- 2
pmapi/src/main/java/com/ningdatech/pmapi/common/handler/GlobalResponseHandler.java View File

@@ -2,7 +2,6 @@ package com.ningdatech.pmapi.common.handler;

import cn.hutool.json.JSONUtil;
import com.ningdatech.basic.model.ApiResponse;
import com.ningdatech.pmapi.common.util.BizUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
@@ -24,7 +23,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
"com.ningdatech.pmapi.projectlib.controller",
"com.ningdatech.pmapi.sys.controller",
"com.ningdatech.pmapi.todocenter.controller",
"com.ningdatech.pmapi.user.controller"
"com.ningdatech.pmapi.user.controller",
})
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {



+ 2
- 1
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java View File

@@ -20,6 +20,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Map;
@@ -69,7 +70,7 @@ public class ConstructionPlanManage {

//首先要判断 项目当前状态 是不是 方案待申报
VUtils.isTrue(!ProjectStatusEnum.PLAN_TO_BE_DECLARED.getCode().equals(projectInfo.getStatus()) ||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage()))
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage()))
.throwMessage("提交失败 该项目不是 待预审状态或者未立项阶段");
//TODO 再判断 该项目是否 真实走完 单位内部审批



+ 2
- 2
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/AnnualPlanLibManage.java View File

@@ -145,7 +145,7 @@ public class AnnualPlanLibManage {
try (InputStream inputStream = file.getInputStream()) {
EasyExcel.read(inputStream, new AnalysisEventListener<AnnualLibImportDTO>() {

private List<Project> records = new ArrayList<>();
private final List<Project> records = new ArrayList<>();

@Override
public void onException(Exception exception, AnalysisContext context) throws Exception {
@@ -179,7 +179,7 @@ public class AnnualPlanLibManage {
project.setBeginTime(dataArr[0].trim());
project.setEndTime(dataArr[1].trim());
project.setProjectIntroduction(data.getProjectIntroduction());
project.setIsFirst(data.getIsFirst().equals("新建") ? 1 : 0);
project.setIsFirst("新建".equals(data.getIsFirst()) ? 1 : 0);
records.add(project);
}



+ 22
- 1
pmapi/src/main/java/com/ningdatech/pmapi/sys/model/enumeration/DataScopeEnum.java View File

@@ -2,9 +2,11 @@ package com.ningdatech.pmapi.sys.model.enumeration;

import lombok.Getter;

import java.util.Arrays;

/**
* <p>
* DataScopeEnum
* 数据权限可见范围枚举
* </p>
*
* @author WendyYang
@@ -28,4 +30,23 @@ public enum DataScopeEnum {
this.code = code;
this.desc = desc;
}

public boolean eq(Integer code) {
return this.code.equals(code);
}

/**
* 根据code获取枚举实例
*
* @param code 编码
* @return {@link DataScopeEnum}
* @author WendyYang
**/
public static DataScopeEnum getByCode(Integer code) {
return Arrays.stream(values())
.filter(w -> w.eq(code))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("无效的数据权限可见范围编码"));
}

}

+ 30
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/constant/LoginTypeEnum.java View File

@@ -0,0 +1,30 @@
package com.ningdatech.pmapi.user.constant;

import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
* @author liuxinxin
* @date 2022/8/17 下午5:55
*/
@AllArgsConstructor
@Getter
@ApiModel("登陆类型")
public enum LoginTypeEnum {
/**
* 浙政钉扫码登陆
*/
DING_QR_LOGIN,

/**
* 手机号验证码登陆
*/
PHONE_VERIFICATION_CODE_LOGIN,

/**
* 账号密码登陆
*/
USERNAME_PASSWORD_LOGIN;

}

+ 0
- 20
pmapi/src/main/java/com/ningdatech/pmapi/user/controller/NdUserAuthController.java View File

@@ -1,20 +0,0 @@
package com.ningdatech.pmapi.user.controller;


import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.stereotype.Controller;

/**
* <p>
* 前端控制器
* </p>
*
* @author Lierbao
* @since 2023-02-01
*/
@Controller
@RequestMapping("/pmapi.user/nd-user-auth")
public class NdUserAuthController {

}

+ 0
- 20
pmapi/src/main/java/com/ningdatech/pmapi/user/controller/NdUserInfoController.java View File

@@ -1,20 +0,0 @@
package com.ningdatech.pmapi.user.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* <p>
* 前端控制器
* </p>
*
* @author Lierbao
* @since 2023-02-01
*/
@Controller
@RequestMapping("/pmapi.user/nd-user-info")
public class NdUserInfoController {


}

+ 9
- 6
pmapi/src/main/java/com/ningdatech/pmapi/user/controller/UserAuthController.java View File

@@ -36,13 +36,16 @@ public class UserAuthController {

private final ObjectMapper objectMapper;

@PostMapping(value = "/login/password", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@ApiOperation(value = "账号密码的登陆方式")
@PostMapping(value = "/login", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@ApiOperation(value = "登陆")
@ApiImplicitParams({
@ApiImplicitParam(name = "username", value = "用户名", required = true, paramType = "form", dataType = "String"),
@ApiImplicitParam(name = "password", value = "密码", required = true, paramType = "form", dataType = "String")})
public void loginByUsernameAndPassword(@RequestParam("username") String username,
@RequestParam("password") String password) {
@ApiImplicitParam(name = "identifier", value = "账号", required = true, paramType = "form", dataType = "String"),
@ApiImplicitParam(name = "credential", value = "凭证", required = true, paramType = "form", dataType = "String"),
@ApiImplicitParam(name = "loginType", value = "DING_QR_LOGIN 浙政钉扫码登陆,PHONE_VERIFICATION_CODE_LOGIN 手机号验证码登陆"
, required = true, paramType = "form", dataType = "String")})
public void loginByUsernameAndPassword(@RequestParam(value = "identifier",required = false) String identifier,
@RequestParam(value = "credential",required = false) String credential,
@RequestParam("loginType") String loginType) {
// 不实现任何内容,只是为了出api文档
}



+ 38
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/manage/UserAuthLoginManage.java View File

@@ -18,6 +18,12 @@ public class UserAuthLoginManage {
private final IUserAuthService iUserAuthService;
private final IUserInfoService iUserInfoService;

/**
* 根据用户名获取
*
* @param username
* @return
*/
public UserFullInfoDTO queryUserInfoInPasswordAuth(String username) {
UserFullInfoDTO userFullInfoDTO = new UserFullInfoDTO();
userFullInfoDTO.setCompanyId(1L);
@@ -27,4 +33,36 @@ public class UserAuthLoginManage {
userFullInfoDTO.setUsername("测试账号");
return userFullInfoDTO;
}

/**
* 根据手机号获取
*
* @param phoneNo
* @return
*/
public UserFullInfoDTO queryUserInfoInPhoneNoAuth(String phoneNo) {
UserFullInfoDTO userFullInfoDTO = new UserFullInfoDTO();
userFullInfoDTO.setCompanyId(1L);
userFullInfoDTO.setUserId(1L);
userFullInfoDTO.setIdentifier("123456");
userFullInfoDTO.setRealName("测试账号");
userFullInfoDTO.setUsername("测试账号");
return userFullInfoDTO;
}

/**
* 根据accountId
*
* @param accountId
* @return
*/
public UserFullInfoDTO queryUserInfoInAccountIdAuth(String accountId) {
UserFullInfoDTO userFullInfoDTO = new UserFullInfoDTO();
userFullInfoDTO.setCompanyId(1L);
userFullInfoDTO.setUserId(1L);
userFullInfoDTO.setIdentifier("123456");
userFullInfoDTO.setRealName("测试账号");
userFullInfoDTO.setUsername("测试账号");
return userFullInfoDTO;
}
}

+ 5
- 8
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/WebSecurityConfig.java View File

@@ -1,13 +1,11 @@
package com.ningdatech.pmapi.user.security.auth;

import com.google.common.collect.Lists;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdJsonUtil;
import com.ningdatech.basic.util.StrPool;
import com.ningdatech.pmapi.common.constant.BizConst;
import com.ningdatech.pmapi.common.constant.CommonConstant;
import com.ningdatech.pmapi.user.security.auth.handler.DefaultExpiredSessionStrategy;
import com.ningdatech.pmapi.user.security.auth.password.UsernamePasswordAuthSecurityConfig;
import com.ningdatech.pmapi.user.security.auth.credential.CredentialAuthSecurityConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
@@ -18,7 +16,6 @@ import org.springframework.security.web.authentication.logout.LogoutSuccessHandl
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;

@@ -31,16 +28,16 @@ import java.util.Set;
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

private final AuthProperties authProperties;
private final UsernamePasswordAuthSecurityConfig usernamePasswordAuthSecurityConfig;
private final CredentialAuthSecurityConfig credentialAuthSecurityConfig;
private final LogoutSuccessHandler logoutSuccessHandler;
private final DefaultExpiredSessionStrategy defaultExpiredSessionStrategy;

public WebSecurityConfig(AuthProperties authProperties,
UsernamePasswordAuthSecurityConfig usernamePasswordAuthSecurityConfig,
CredentialAuthSecurityConfig credentialAuthSecurityConfig,
@Qualifier(value = "defaultLogoutSuccessHandler") LogoutSuccessHandler logoutSuccessHandler,
DefaultExpiredSessionStrategy defaultExpiredSessionStrategy) {
this.authProperties = authProperties;
this.usernamePasswordAuthSecurityConfig = usernamePasswordAuthSecurityConfig;
this.credentialAuthSecurityConfig = credentialAuthSecurityConfig;
this.logoutSuccessHandler = logoutSuccessHandler;
this.defaultExpiredSessionStrategy = defaultExpiredSessionStrategy;
}
@@ -50,7 +47,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
assemblerPreAuthUrls(http);
http.formLogin()
.loginPage(authProperties.getAuthRequireUrl())
.and().apply(usernamePasswordAuthSecurityConfig)
.and().apply(credentialAuthSecurityConfig)
.and()
.authorizeRequests().antMatchers(authProperties.getIgnoreAuthUrlsArray()).permitAll().anyRequest()
.authenticated().and()


+ 11
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/constants/UserDeatilsServiceConstant.java View File

@@ -0,0 +1,11 @@
package com.ningdatech.pmapi.user.security.auth.constants;

/**
* @author liuxinxin
* @date 2023/2/14 上午11:29
*/

public class UserDeatilsServiceConstant {

public static final String USER_DETAILS_SERVICE_SEPARATOR = "@###@";
}

pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/PasswordLoginUserDetailService.java → pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/AccountIdLoginUserDetailService.java View File

@@ -1,4 +1,4 @@
package com.ningdatech.pmapi.user.security.auth.password;
package com.ningdatech.pmapi.user.security.auth.credential;


import com.ningdatech.pmapi.user.manage.UserAuthLoginManage;
@@ -16,17 +16,17 @@ import java.util.Objects;
* @date 2022/9/30 上午9:49
*/

@Service("passwordLoginUserDetailService")
@Service("accountIdLoginUserDetailService")
@RequiredArgsConstructor
public class PasswordLoginUserDetailService implements UserDetailsService {
public class AccountIdLoginUserDetailService implements UserDetailsService {

private final UserAuthLoginManage userAuthLoginManage;

@Override
public UserInfoDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserFullInfoDTO userFullInfoDTO = userAuthLoginManage.queryUserInfoInPasswordAuth(username);
public UserInfoDetails loadUserByUsername(String accountId) throws UsernameNotFoundException {
UserFullInfoDTO userFullInfoDTO = userAuthLoginManage.queryUserInfoInAccountIdAuth(accountId);
if (Objects.isNull(userFullInfoDTO)) {
throw new UsernameNotFoundException(String.format("%s user not exist", username));
throw new UsernameNotFoundException(String.format("%s user not exist", accountId));
}
UserInfoDetails userInfoDetails = new UserInfoDetails();
userInfoDetails.setUserId(userFullInfoDTO.getUserId());

+ 108
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthFilter.java View File

@@ -0,0 +1,108 @@
package com.ningdatech.pmapi.user.security.auth.credential;

import com.ningdatech.basic.exception.BizException;
import com.ningdatech.pmapi.user.constant.LoginTypeEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
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;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @Author LiuXinXin
* @Date 2020/8/3 8:46 下午
* @Version 1.0
**/
public class CredentialAuthFilter extends AbstractAuthenticationProcessingFilter {

private boolean postOnly = true;

private static final String IDENTIFIER_PARAMETER = "identifier";
private static final String CREDENTIAL_PARAMETER = "credential";
private static final String LOGIN_TYPE_PARAMETER = "loginType";


// ~ Constructors
// ===================================================================================================

public CredentialAuthFilter(String processingUrl) {
super(new AntPathRequestMatcher(processingUrl, HttpMethod.POST.name()));
}

// ~ Methods
// ========================================================================================================

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
throw new AuthenticationServiceException("请求方法错误");
}
String identifier = request.getParameter(IDENTIFIER_PARAMETER);
String credential = request.getParameter(CREDENTIAL_PARAMETER);
String loginType = request.getParameter(LOGIN_TYPE_PARAMETER);
if (StringUtils.isBlank(loginType)) {
throw new BadCredentialsException("登陆类型不能为空");
}
paramValid(identifier, credential, loginType);


identifier = trim(identifier);
credential = trim(credential);
loginType = trim(loginType);
try {
CredentialAuthToken authRequest = new CredentialAuthToken(identifier, credential, loginType);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
} catch (AuthenticationException e) {
throw new BadCredentialsException("账号或密码错误");
} catch (BizException e) {
throw new BadCredentialsException(e.getMessage());
} catch (Exception e) {
throw new InternalAuthenticationServiceException("授权失败:", e);
}
}

protected void setDetails(HttpServletRequest request, CredentialAuthToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}

private void paramValid(String identifier, String credential, String loginType) {
LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(loginType);
switch (loginTypeEnum) {
case DING_QR_LOGIN: {
if (StringUtils.isBlank(credential)) {
throw new BadCredentialsException("浙政钉扫码登陆 授权码 不能为空 credential");
}
}
break;
case USERNAME_PASSWORD_LOGIN: {
if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) {
throw new BadCredentialsException("账号密码登陆 账号密码不能为空 identifier credential");
}
}
break;
case PHONE_VERIFICATION_CODE_LOGIN: {
if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) {
throw new BadCredentialsException("手机号验证码登陆 手机号或验证码不能为空 identifier credential");
}
}
break;
}
}

private String trim(String trimStr) {
if (StringUtils.isNotBlank(trimStr)) {
return trimStr.trim();
}
return null;
}
}

+ 103
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthProvider.java View File

@@ -0,0 +1,103 @@
package com.ningdatech.pmapi.user.security.auth.credential;

import com.ningdatech.basic.model.GenericResult;
import com.ningdatech.pmapi.user.constant.LoginTypeEnum;
import com.ningdatech.pmapi.user.security.auth.constants.UserDeatilsServiceConstant;
import com.ningdatech.zwdd.client.ZwddAuthClient;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.Objects;

/**
* @Author LiuXinXin
* @Date 2020/8/3 8:55 下午
* @Version 1.0
**/
public class CredentialAuthProvider implements AuthenticationProvider {

private UserDetailsService userDetailsService;

private PasswordEncoder passwordEncoder;

private ZwddAuthClient zwddAuthClient;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!(authentication instanceof CredentialAuthToken)) {
throw new RuntimeException("CustomAuthProvider 只支持 CustomAuthToken");
}
CredentialAuthToken authenticationToken = (CredentialAuthToken) authentication;
String principal = (String) authenticationToken.getPrincipal();

UserDetails user = null;
LoginTypeEnum loginTypeEnum = authenticationToken.getLoginTypeEnum();
switch (loginTypeEnum) {
case DING_QR_LOGIN: {
String code = (String) authenticationToken.getCredentials();
GenericResult<String> accountResult = zwddAuthClient.getAccountId(code);
if (!accountResult.isSuccess()) {
throw new BadCredentialsException("login fail! 浙政钉校验失败");
}
String accountId = accountResult.getData();
if (Objects.isNull(accountId)) {
throw new BadCredentialsException("login fail! 浙政钉校验失败");
}
user = userDetailsService.loadUserByUsername(accountId + UserDeatilsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR + loginTypeEnum.name());
}
break;
case PHONE_VERIFICATION_CODE_LOGIN: {
// TODO 校验短信验证码
user = userDetailsService.loadUserByUsername(principal + UserDeatilsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR + loginTypeEnum.name());
}
break;
case USERNAME_PASSWORD_LOGIN: {
user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
if (user == null) {
throw new InternalAuthenticationServiceException("can not get user info!");
}
// 账号密码登陆 更改
additionalAuthenticationChecks(user, authenticationToken);
}
break;
}
// 将用户定义的user放入token中,这样可以在session中查询到所有自定义的用户信息
return new CredentialAuthToken(user, user.getPassword(), user.getAuthorities());
}

protected void additionalAuthenticationChecks(UserDetails userDetails, CredentialAuthToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
throw new BadCredentialsException("login fail! password is null");
}
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
throw new BadCredentialsException("login fail! password is error");
}
}


@Override
public boolean supports(Class<?> authentication) {
return CredentialAuthToken.class.isAssignableFrom(authentication);
}

public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}

public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}

public void setZwddAuthClient(ZwddAuthClient zwddAuthClient) {
this.zwddAuthClient = zwddAuthClient;
}

}

pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthSecurityConfig.java → pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthSecurityConfig.java View File

@@ -1,6 +1,7 @@
package com.ningdatech.pmapi.user.security.auth.password;
package com.ningdatech.pmapi.user.security.auth.credential;

import com.ningdatech.pmapi.user.security.auth.AuthProperties;
import com.ningdatech.zwdd.client.ZwddAuthClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
@@ -18,7 +19,7 @@ import org.springframework.stereotype.Component;
* 账号密码登陆的认证配置
*/
@Component
public class UsernamePasswordAuthSecurityConfig
public class CredentialAuthSecurityConfig
extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

@Autowired
@@ -30,8 +31,8 @@ public class UsernamePasswordAuthSecurityConfig
protected AuthenticationFailureHandler defaultLoginFailureHandler;

@Autowired
@Qualifier(value = "passwordLoginUserDetailService")
private UserDetailsService passwordLoginUserDetailService;
@Qualifier(value = "credentialLoginUserDetailService")
private UserDetailsService credentialLoginUserDetailService;

@Autowired
private PasswordEncoder passwordEncoder;
@@ -41,20 +42,26 @@ public class UsernamePasswordAuthSecurityConfig

private AuthenticationManager authenticationManager;

@Autowired
private ZwddAuthClient zwddAuthClient;

@Override
public void configure(HttpSecurity http) throws Exception {
UsernamePasswordAuthFilter usernamePasswordAuthFilter =
new UsernamePasswordAuthFilter(authProperties.getPasswordLoginUrl());
CredentialAuthFilter credentialAuthFilter =
new CredentialAuthFilter(authProperties.getPasswordLoginUrl());
authenticationManager = http.getSharedObject(AuthenticationManager.class);
usernamePasswordAuthFilter.setAuthenticationManager(authenticationManager);
usernamePasswordAuthFilter.setAuthenticationSuccessHandler(defaultLoginSuccessHandler);
usernamePasswordAuthFilter.setAuthenticationFailureHandler(defaultLoginFailureHandler);
credentialAuthFilter.setAuthenticationManager(authenticationManager);
credentialAuthFilter.setAuthenticationSuccessHandler(defaultLoginSuccessHandler);
credentialAuthFilter.setAuthenticationFailureHandler(defaultLoginFailureHandler);

UsernamePasswordAuthProvider authenticationProvider = new UsernamePasswordAuthProvider();
authenticationProvider.setUserDetailsService(passwordLoginUserDetailService);
CredentialAuthProvider authenticationProvider = new CredentialAuthProvider();
authenticationProvider.setUserDetailsService(credentialLoginUserDetailService);
// 确保对密码进行加密的encoder和解密的encoder相同
authenticationProvider.setPasswordEncoder(passwordEncoder);
http.authenticationProvider(authenticationProvider).addFilterAfter(usernamePasswordAuthFilter,
// 传入浙政钉client
authenticationProvider.setZwddAuthClient(zwddAuthClient);

http.authenticationProvider(authenticationProvider).addFilterAfter(credentialAuthFilter,
UsernamePasswordAuthenticationFilter.class);
}


pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthToken.java → pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthToken.java View File

@@ -1,5 +1,6 @@
package com.ningdatech.pmapi.user.security.auth.password;
package com.ningdatech.pmapi.user.security.auth.credential;

import com.ningdatech.pmapi.user.constant.LoginTypeEnum;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
@@ -11,7 +12,7 @@ import java.util.Collection;
* @Date 2020/8/3 8:52 下午
* @Version 1.0
**/
public class UsernamePasswordAuthToken extends AbstractAuthenticationToken {
public class CredentialAuthToken extends AbstractAuthenticationToken {

private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

@@ -19,16 +20,18 @@ public class UsernamePasswordAuthToken extends AbstractAuthenticationToken {

private final Object credentials;

private final LoginTypeEnum loginTypeEnum;

/**
* This constructor can be safely used by any code that wishes to create a
* <code>UsernamePasswordAuthenticationToken</code>, as the {@link #isAuthenticated()} will return
* <code>false</code>.
*/
public UsernamePasswordAuthToken(String principal, String credentials) {
public CredentialAuthToken(String principal, String credentials, String loginTypeEnum) {
super(null);
this.principal = principal;
this.credentials = credentials;
this.loginTypeEnum = LoginTypeEnum.valueOf(loginTypeEnum);
setAuthenticated(false);
}

@@ -40,15 +43,20 @@ public class UsernamePasswordAuthToken extends AbstractAuthenticationToken {
* @param principal
* @param authorities
*/
public UsernamePasswordAuthToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
public CredentialAuthToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
this.loginTypeEnum = null;
// must use super, as we override
super.setAuthenticated(true);
}

public LoginTypeEnum getLoginTypeEnum() {
return this.loginTypeEnum;
}

@Override
public Object getCredentials() {
return this.credentials;

+ 67
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialLoginUserDetailService.java View File

@@ -0,0 +1,67 @@
package com.ningdatech.pmapi.user.security.auth.credential;


import com.ningdatech.pmapi.user.constant.LoginTypeEnum;
import com.ningdatech.pmapi.user.manage.UserAuthLoginManage;
import com.ningdatech.pmapi.user.security.auth.constants.UserDeatilsServiceConstant;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.security.auth.model.UserInfoDetails;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Objects;

/**
* @author LiuXinXin
* @date 2022/9/30 上午9:49
*/

@Service("credentialLoginUserDetailService")
@RequiredArgsConstructor
public class CredentialLoginUserDetailService implements UserDetailsService {

private final UserAuthLoginManage userAuthLoginManage;

@Override
public UserInfoDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String[] split = username.split(UserDeatilsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR);
username = split[0];
String loginTypeStr = split[1];
LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(loginTypeStr);

UserFullInfoDTO userFullInfoDTO = null;
switch (loginTypeEnum) {
case PHONE_VERIFICATION_CODE_LOGIN: {
userFullInfoDTO = userAuthLoginManage.queryUserInfoInPhoneNoAuth(username);
}
break;
case USERNAME_PASSWORD_LOGIN: {
userFullInfoDTO = userAuthLoginManage.queryUserInfoInPasswordAuth(username);
}
break;
case DING_QR_LOGIN: {
userFullInfoDTO = userAuthLoginManage.queryUserInfoInAccountIdAuth(username);
}
break;
default: {
throw new UsernameNotFoundException(String.format("%s user not exist", username));
}
}

if (Objects.isNull(userFullInfoDTO)) {
throw new UsernameNotFoundException(String.format("%s user not exist", username));
}
UserInfoDetails userInfoDetails = new UserInfoDetails();
userInfoDetails.setUserId(userFullInfoDTO.getUserId());
userInfoDetails.setUsername(userFullInfoDTO.getUsername());
userInfoDetails.setRealName(userFullInfoDTO.getRealName());
userInfoDetails.setRole(userFullInfoDTO.getRole());
userInfoDetails.setRegionCode(userFullInfoDTO.getRegionCode());
userInfoDetails.setCompanyId(userFullInfoDTO.getCompanyId());
userInfoDetails.setIdentifier(userFullInfoDTO.getIdentifier());
userInfoDetails.setPassword(userFullInfoDTO.getCredential());
return userInfoDetails;
}
}

+ 0
- 71
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthFilter.java View File

@@ -1,71 +0,0 @@
package com.ningdatech.pmapi.user.security.auth.password;

import com.ningdatech.basic.exception.BizException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @Author LiuXinXin
* @Date 2020/8/3 8:46 下午
* @Version 1.0
**/
public class UsernamePasswordAuthFilter extends AbstractAuthenticationProcessingFilter {

private boolean postOnly = true;

private static final String USERNAME_PARAMETER = "username";
private static final String PASSWORD_PARAMETER = "password";


// ~ Constructors
// ===================================================================================================

public UsernamePasswordAuthFilter(String processingUrl) {
super(new AntPathRequestMatcher(processingUrl, HttpMethod.POST.name()));
}

// ~ Methods
// ========================================================================================================

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
throw new AuthenticationServiceException("请求方法错误");
}
String username = request.getParameter(USERNAME_PARAMETER);
String password = request.getParameter(PASSWORD_PARAMETER);
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
throw new UsernameNotFoundException("用户名或密码不能为空");
}
username = username.trim();
password = password.trim();
try {
UsernamePasswordAuthToken authRequest = new UsernamePasswordAuthToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
} catch (AuthenticationException e) {
throw new BadCredentialsException("账号或密码错误");
} catch (BizException e) {
throw new BadCredentialsException(e.getMessage());
} catch (Exception e) {
throw new InternalAuthenticationServiceException("授权失败:", e);
}
}

protected void setDetails(HttpServletRequest request, UsernamePasswordAuthToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
}

+ 0
- 65
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthProvider.java View File

@@ -1,65 +0,0 @@
package com.ningdatech.pmapi.user.security.auth.password;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
* @Author LiuXinXin
* @Date 2020/8/3 8:55 下午
* @Version 1.0
**/
public class UsernamePasswordAuthProvider implements AuthenticationProvider {

private UserDetailsService userDetailsService;

private PasswordEncoder passwordEncoder;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!(authentication instanceof UsernamePasswordAuthToken)) {
throw new RuntimeException("CustomAuthProvider 只支持 CustomAuthToken");
}
UsernamePasswordAuthToken authenticationToken = (UsernamePasswordAuthToken) authentication;

UserDetails user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
if (user == null) {
throw new InternalAuthenticationServiceException("can not get user info!");
}
// TODO 开发使用暂时关闭账号密码验证
// additionalAuthenticationChecks(user, authenticationToken);
// 校验用户是否有当前端的登陆权限
// 将用户定义的user放入token中,这样可以在session中查询到所有自定义的用户信息
return new UsernamePasswordAuthToken(user, user.getPassword(), user.getAuthorities());
}

protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
throw new BadCredentialsException("login fail! password is null");
}
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
throw new BadCredentialsException("login fail! password is error");
}
}

@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthToken.class.isAssignableFrom(authentication);
}

public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}

public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}

}

+ 5
- 13
pmapi/src/main/resources/integration/zwdd-dev.yml View File

@@ -1,20 +1,12 @@
#专有钉钉
integration:
zzd:
zwdd:
#扫码
app-auth-key: expert-base_dingoa-c5nnefYVnie
app-auth-secret: nm8qtST8uK431HYrjr7srcE23sT4889QgMcYFM3L
# #免登/获取信息
# app-key: file-manage-4Mjx9358wuxjyYFjY3
# app-secret: hE41938wqyQ5LOpc1QDRA9e7gb5YugoClWD3nY4O
app-auth-key: ls-rebuild_dingoa-rgeWs3YVr26z
app-auth-secret: 37qCe6ylNMW0N8K2741z0c2b9vJP2gtuMRQQtZ9P
#免登/获取信息
app-key: ls_rebuild-10c8n5X0707yFV7jURr
app-secret: gN8J3WazyXLMWKDuFmx6C4yaH5lFUY41x8rYLLo6
#专有钉钉在开发管理工作台,右键查看网页源码realmId: '31141',浙政钉固定196729
tenantId: 31141
domain: openplatform.dg-work.cn

# integration.zzd.enabled=true
# #扫码
# integration.zzd.app-auth-key=file-manage_dingoa-zte2LbiAfIj
# integration.zzd.app-auth-secret=H794aFZf271QbfUr50pbBpBTlXSrWIP71q9RTR34
# integration.zzd.domain=openplatform.dg-work.cn
domain: openplatform.dg-work.cn

+ 11
- 10
pmapi/src/main/resources/integration/zwdd-prod.yml View File

@@ -1,11 +1,12 @@
#专有钉钉
ding:
#扫码
app-auth-key: expert-base_dingoa-c5nnefYVnie
app-auth-secret: nm8qtST8uK431HYrjr7srcE23sT4889QgMcYFM3L
# #免登/获取信息
app-key: file-manage-4Mjx9358wuxjyYFjY3
app-secret: hE41938wqyQ5LOpc1QDRA9e7gb5YugoClWD3nY4O
#专有钉钉在开发管理工作台,右键查看网页源码realmId: '31141',浙政钉固定196729
tenantId: 31141
domain: openplatform.dg-work.cn
integration:
zwdd:
#扫码
app-auth-key: ls-rebuild_dingoa-rgeWs3YVr26z
app-auth-secret: 37qCe6ylNMW0N8K2741z0c2b9vJP2gtuMRQQtZ9P
#免登/获取信息
app-key: ls_rebuild-10c8n5X0707yFV7jURr
app-secret: gN8J3WazyXLMWKDuFmx6C4yaH5lFUY41x8rYLLo6
#专有钉钉在开发管理工作台,右键查看网页源码realmId: '31141',浙政钉固定196729
tenantId: 31141
domain: openplatform.dg-work.cn

+ 1
- 1
pmapi/src/main/resources/security/auth-dev.yml View File

@@ -2,7 +2,7 @@ security:
auth:
auth-require-url: /api/v1/user/auth/auth-require
invalid-session-url: /api/v1/user/auth/invalid-session
password-login-url: /api/v1/user/auth/login/password
password-login-url: /api/v1/user/auth/login
logout-url: /api/v1/user/auth/logout
ignore-auth-urls:
- /v2/api-docs


+ 1
- 1
pmapi/src/main/resources/security/auth-prod.yml View File

@@ -2,7 +2,7 @@ security:
auth:
auth-require-url: /api/v1/user/auth/auth-require
invalid-session-url: /api/v1/user/auth/invalid-session
password-login-url: /api/v1/user/auth/login/password
password-login-url: /api/v1/user/auth/login
logout-url: /api/v1/user/auth/logout
ignore-auth-urls:
- /v2/api-docs


Loading…
Cancel
Save