我有一個正在使用(電子郵件/密碼)登錄程序的應用程式。現在我已經實作了 LDAP 身份驗證。一個用戶進入authenticate行程,如果資料庫不認識他,就進入ldap行程,如果成功,那么我們在資料庫中創建他的賬戶。接下來我們收到 JWT 令牌。
問題是,如果我們重試連接,new UsernamePasswordAuthenticationToken(email, password);則會回傳經過身份驗證的 false。但是憑據還可以,它應該可以作業...
我不明白發生了什么..用戶顯示在資料庫中,密碼加密..
@Service
@RequiredArgsConstructor
public class OpenLdapAuthenticationProvider implements AuthenticationProvider {
@Value("${spring.ldap.enabled}")
private Boolean enableLDAP;
@Autowired
private LdapTemplate ldapTemplate;
private final UserService userService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String email = authentication.getName();
String password = authentication.getCredentials().toString();
// This method returns authenticated false !
Authentication authenticationWithDatabase = this.tryAuthWithDatabase(email, password);
if (authenticationWithDatabase.isAuthenticated() == false) {
if (enableLDAP == true) {
boolean authenticationWithLdap = this.tryAuthWithLdap(email, password);
if (authenticationWithLdap == true) {
UserDataDTO userDataDTO = this.retrieveUserInformationFromLDAP(email);
userDataDTO.setEmail(email);
userDataDTO.setPassword(password);
List<AppUserRole> userRoles = new ArrayList<>();
userRoles.add(AppUserRole.ROLE_DEV_VIEW);
userDataDTO.setAppUserRoles(userRoles);
boolean trySignup = userService.signup(userDataDTO);
if (trySignup == true) {
return this.tryAuthWithDatabase(email, password);
} else {
throw new InternalServerErrorException("Your account is not in database. Sign in with LDAP was OK, but registration failed. This should not happen.");
}
} else {
throw new UnAuthorizedErrorException(
"The connection has been refused (by the database and ldap). Check your credentials.");
}
} else {
throw new UnAuthorizedErrorException(
"The connection has been refused by the database and cannot be made by ldap because it has been disabled.");
}
} else {
return authenticationWithDatabase;
}
}
private Authentication tryAuthWithDatabase(String email, String password) {
return new UsernamePasswordAuthenticationToken(email, password);
}
private boolean tryAuthWithLdap(String email, String password) {
Filter filter = new EqualsFilter("mail", email); // mail = le champs dans l'arbre LDAP
return ldapTemplate.authenticate(LdapUtils.emptyLdapName(), filter.encode(), password);
}
public UserDataDTO retrieveUserInformationFromLDAP(String email) {
LdapQuery query = LdapQueryBuilder.query().where("objectClass").is("user").and("mail").is(email);
return ldapTemplate.search(query,
(AttributesMapper<UserDataDTO>) attributes ->
UserDataDTO.builder()
.name(attributes.get("givenName").get().toString())
.surname(attributes.get("sn").get().toString())
.username(attributes.get("displayName").get().toString())
.team(attributes.get("department").get().toString())
.build()).get(0);
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private JwtTokenProvider jwtTokenProvider;
@Autowired
private OpenLdapAuthenticationProvider openLdapAuthenticationProvider;
public WebSecurityConfig(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(this.openLdapAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(corsFilter(), ChannelProcessingFilter.class);
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
.antMatchers("/api/v3/authentificate").permitAll()
.antMatchers("/api/v3/signup").permitAll()
.anyRequest().authenticated();
http.apply(new JwtTokenFilterConfigurer(jwtTokenProvider));
}
@Override
public void configure(WebSecurity web) throws Exception {
// Allow swagger to be accessed without authentication
web.ignoring().antMatchers("/v3/api-docs/**")//
.antMatchers("/swagger-resources/**")//
.antMatchers("/swagger-ui/**")
.antMatchers("/swagger-ui.html");
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
@Configuration
public class GenericBeanConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
}
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
}
感謝您的幫助,我真的不明白發生了什么..
uj5u.com熱心網友回復:
如果您檢查UsernamePasswordAuthenticationToken.class,您將看到 2 個建構式:
/**
* 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 UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
setAuthenticated(false);
}
/**
* This constructor should only be used by <code>AuthenticationManager</code> or
* <code>AuthenticationProvider</code> implementations that are satisfied with
* producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
* authentication token.
* @param principal
* @param credentials
* @param authorities
*/
public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true); // must use super, as we override
}
在其檔案中可以看到相同的內容
Spring security 的默認實作期望您為您的用戶實體提供至少一個授予權限
發生這種情況是因為身份驗證提供程式接收到一個身份驗證物件,該物件未經過身份驗證,僅作為輸入用戶名和密碼,通過應用其邏輯(從資料庫中獲取等),如果結果匹配,則回傳身份驗證物件用戶名、密碼及其權限,如果不匹配則回傳同一個輸入物件
要解決您的問題,您可以嘗試以下純說明性代碼:
// omitted code above
private Authentication tryAuthWithDatabase(String email, String password) {
// call your database or repository or service
// var fetchData receives the object from database
// perform token the matching against the fetch data
if( resultMatches ) {
return new UsernamePasswordAuthenticationToken(email, password, fetchData.getAuthorities() );
}
else {
return new UsernamePasswordAuthenticationToken( email, password );
}
}
// omitted code bellow
我希望我有所幫助。讓我知道你是否成功了。干杯!
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/436102.html
上一篇:react中基于條件的路由
