一、登陸獲取token
# 新增 CustomUserDetailsService 接口并繼承 UserDetailsService
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
/**
* @Author ds
* @Date 2023/4/28
*/
public interface CustomUserDetailsService extends UserDetailsService {
/**
* 繼承原來的 UserDetailsService 新增自定義方法
* @param var1 微信id 或 公證員手機(jī)號(hào)
* @param var2 公證處id
* @param var3 用戶類型
* @return
* @throws UsernameNotFoundException
*/
UserDetails loadUserByUsername(String var1, String var2 ,String var3) throws UsernameNotFoundException;
}
# 實(shí)現(xiàn) CustomUserDetailsService 自定義方法
import com.deepnotary.dict.UserType;
import com.deepnotary.enotary.dao.PlNpoUserDao;
import com.deepnotary.enotary.dao.PlUserDao;
import com.deepnotary.enotary.entity.PlNpoUserEntity;
import com.deepnotary.enotary.entity.PlUserEntity;
import com.deepnotary.enotary.user.service.CustomUserDetailsService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @Author ds
* @Date 2023/4/28
*/
@Slf4j
@Component
public class UserDetailsServiceImpl implements CustomUserDetailsService {
@Autowired
private PlUserDao plUserDao;
@Autowired
private PlNpoUserDao plNpoUserDao;
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* 實(shí)現(xiàn) CustomUserDetailsService 自定義方法烫饼,獲取用戶
* @param var1 微信id 或 公證員手機(jī)號(hào)
* @param var2 公證處id
* @param var3 用戶類型
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String var1, String var2 ,String var3) throws UsernameNotFoundException {
logger.info("miniapp-oauth loadUserByUsername() : var1 : {} , va2 : {}, va3 : {}" , var1 , var2 , var3);
// 微信用戶
if(var3.equals(UserType.WX_USER.code())){
// 1.獲取用戶 查詢數(shù)據(jù)庫中微信用戶
PlUserEntity plUserEntity = plUserDao.getByWxOpenId(var1);
if (plUserEntity == null) {
throw new UsernameNotFoundException("用戶不存在嵌纲,請(qǐng)確認(rèn)openId是否正確:" + var1);
}
String password = plUserEntity.getPassword();
logger.info(UserType.WX_USER.message() + " password : " + password);
logger.info(UserType.WX_USER.message() + " ecrypt password : " + new BCryptPasswordEncoder().encode(password));
// 2.獲取用戶可訪問權(quán)限信息 權(quán)限集合
List<GrantedAuthority> authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,gzy,zl");
// 3.構(gòu)造UserDetails信息并返回 注意村怪,這里數(shù)據(jù)庫中存儲(chǔ)的是加密的,所以不需要加密;
return new User(var1, password, authorityList);
}else if(var3.equals(UserType.NPO_USER.code())){
// 1.獲取用戶 查詢數(shù)據(jù)庫中公證員用戶
PlNpoUserEntity plNpoUserEntity = plNpoUserDao.getUserForLogin(var2 , var1);
if (plNpoUserEntity == null) {
throw new UsernameNotFoundException("用戶不存在阿纤,請(qǐng)確認(rèn)cellphone是否正確:" + var1);
}
String password = plNpoUserEntity.getPasswd();
logger.info(UserType.NPO_USER.message() + " password : " + password);
logger.info(UserType.NPO_USER.message() + " ecrypt password : " + new BCryptPasswordEncoder().encode(password));
// 2.獲取用戶可訪問權(quán)限信息 權(quán)限集合
List<GrantedAuthority> authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,gzy,zl");
// 3.構(gòu)造UserDetails信息并返回 ,注意,這里數(shù)據(jù)庫中存儲(chǔ)的是未加密的八拱,所以這里需要加密阵赠;
return new User(var1, new BCryptPasswordEncoder().encode(password), authorityList);
// return new User(var1, password, authorityList);
}else {
throw new UsernameNotFoundException("用戶不存在,請(qǐng)確認(rèn)是否添加用戶類型 :" + var2);
}
}
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return null;
}
}
# 替換所有 userDetailsService 為 CustomUserDetailsService
import com.deepnotary.enotary.user.service.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* 自定義web安全配置類
*/
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public CustomUserDetailsService customUserDetailsService;
@Bean(name="customAuthenticationProvider")
public AuthenticationProvider customAuthenticationProvider() {
CustomAuthenticationProvider customAuthenticationProvider= new CustomAuthenticationProvider();
customAuthenticationProvider.setUserDetailsService(customUserDetailsService);
customAuthenticationProvider.setHideUserNotFoundExceptions(false);
customAuthenticationProvider.setPasswordEncoder(passwordEncoder());
return customAuthenticationProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 認(rèn)證管理
* @return 認(rèn)證管理對(duì)象
* @throws Exception 認(rèn)證異常信息
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 允許匿名訪問所有接口 主要是 oauth 接口
* @param http HTTP協(xié)議安全配置實(shí)例
* @throws Exception 設(shè)置異常
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/miniapp/pl/**").permitAll()
.and().authorizeRequests().antMatchers("/miniapp/npo/user").permitAll();
}
/**
* 安全攔截機(jī)制(最重要)
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) {
// 放行
web.ignoring().antMatchers(
"/error",
"/**/**.html",
"/static/**",
"/v2/api-docs/**",
"/swagger-resources/**",
"/webjars/**",
"/favicon.ico",
"/miniapp-oauth/**",
"/test/**",
"/miniapp/wx/onLogin"
);
}
}
# 1)自定義 CustomAuthenticationProvider肌稻,并繼承 AbstractUserDetailsAuthenticationProvider 清蚀;
# 2)復(fù)制org.springframework.security.authentication.dao.DaoAuthenticationProvider 的代碼;
# 3)修改retrieveUser()方法爹谭,其他不需要?jiǎng)樱?
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
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.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.Assert;
/**
* @Author ds
* @Date 2023/5/4
*/
public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
private PasswordEncoder passwordEncoder;
private volatile String userNotFoundEncodedPassword;
private UserDetailsService userDetailsService;
private UserDetailsPasswordService userDetailsPasswordService;
public CustomAuthenticationProvider() {
this.setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
}
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
if (authentication.getCredentials() == null) {
this.logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
} else {
String presentedPassword = authentication.getCredentials().toString();
if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
this.logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
}
protected void doAfterPropertiesSet() throws Exception {
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
}
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
this.prepareTimingAttackProtection();
try {
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
} else {
return loadedUser;
}
} catch (UsernameNotFoundException var4) {
this.mitigateAgainstTimingAttack(authentication);
throw var4;
} catch (InternalAuthenticationServiceException var5) {
throw var5;
} catch (Exception var6) {
throw new InternalAuthenticationServiceException(var6.getMessage(), var6);
}
}
protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) {
boolean upgradeEncoding = this.userDetailsPasswordService != null && this.passwordEncoder.upgradeEncoding(user.getPassword());
if (upgradeEncoding) {
String presentedPassword = authentication.getCredentials().toString();
String newPassword = this.passwordEncoder.encode(presentedPassword);
user = this.userDetailsPasswordService.updatePassword(user, newPassword);
}
return super.createSuccessAuthentication(principal, authentication, user);
}
private void prepareTimingAttackProtection() {
if (this.userNotFoundEncodedPassword == null) {
this.userNotFoundEncodedPassword = this.passwordEncoder.encode("userNotFoundPassword");
}
}
private void mitigateAgainstTimingAttack(UsernamePasswordAuthenticationToken authentication) {
if (authentication.getCredentials() != null) {
String presentedPassword = authentication.getCredentials().toString();
this.passwordEncoder.matches(presentedPassword, this.userNotFoundEncodedPassword);
}
}
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
this.passwordEncoder = passwordEncoder;
this.userNotFoundEncodedPassword = null;
}
protected PasswordEncoder getPasswordEncoder() {
return this.passwordEncoder;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
protected UserDetailsService getUserDetailsService() {
return this.userDetailsService;
}
public void setUserDetailsPasswordService(UserDetailsPasswordService userDetailsPasswordService) {
this.userDetailsPasswordService = userDetailsPasswordService;
}
}
# 調(diào)用獲取token接口
{
"status": 0,
"message": "登錄成功",
"recvTime": "20230505134843114",
"respTime": "20230505134843517",
"extendData": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJkcyIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2ODM4NzAzODQsImF1dGhvcml0aWVzIjpbImFkbWluIiwiZ3p5IiwiemwiXSwianRpIjoiOTc5ZDVkODUtMDA2Ni00NDg0LWE2ZDctYzlhYTc0M2Q5ZTBlIiwiY2xpZW50X2lkIjoidXNlci1jbGllbnQiLCJ1c2VybmFtZSI6ImRzIn0.auIMJJL6wZY6a4sCbZUINCDVa4QpgzDd3NEOSc1pBw4"
}
}
# 參考
https://www.cnblogs.com/dw3306/p/13533973.html
https://blog.csdn.net/weixin_43909881/article/details/104925068
http://www.reibang.com/p/fa5915a49cc3
http://www.reibang.com/p/45f9707b1792