在我们之前的文章中,我们分别使用 BASIC_AUTH
、JWT_AUTH
和 LDAP_AUTH
配置文件实现了基本身份验证、JWT 身份验证、LDAP 身份验证。此外,我们已经看到如何使用 NO_AUTH``profile.
禁用 Spring Security
但是,有时我们的应用程序可能需要在单个配置文件中支持多个身份验证。例如,如果一个应用程序同时被内部用户和外部用户使用,那么内部用户可以使用 LDAP 身份验证,外部用户可以使用基于基本/JWT 令牌的身份验证。因此,我们将在 Spring Security 中创建一个 MULTI_AUTH
配置文件并配置多个身份验证提供程序。这样,用户就可以使用在请求的 Authorization 标头中传递的基本身份验证或 LDAP 身份验证或 JWT 令牌登录。
为多重身份验证配置文件创建常量
package com.javachinna.config;
public class Profiles {
private Profiles() {
}
public static final String NO_AUTH = "noauth";
public static final String BASIC_AUTH = "basicauth";
public static final String JWT_AUTH = "jwtauth";
public static final String LDAP_AUTH = "ldapauth";
public static final String MULTI_AUTH = "multiauth";
}
@Profile(Profiles.MULTI_AUTH)
注释仅用于在应用程序使用“multiauth
”配置文件运行时启用多个身份验证提供程序。
MultiAuthSecurityConfig
类扩展了 WebSecurityConfigurerAdapter
以使用多个身份验证提供程序配置 Spring Security。
当定义了多个身份验证提供程序时,将按照它们声明的顺序查询这些提供程序。因此,如果一个身份验证失败,那么它将转移到下一个身份验证提供程序。
package com.javachinna.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.LdapShaPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.javachinna.model.Role;
import lombok.RequiredArgsConstructor;
@Profile(Profiles.MULTI_AUTH)
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class MultiAuthSecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final UserDetailsService jwtUserDetailsService;
private final JwtRequestFilter jwtRequestFilter;
private final LdapUserAuthoritiesPopulator ldapUserAuthoritiesPopulator;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// Returns LdapAuthenticationProviderConfigurer to allow customization of the
// LDAP authentication
auth.ldapAuthentication()
// Pass the LDAP patterns for finding the username.
// The key "{0}" will be substituted with the username
.userDnPatterns("uid={0},ou=users")
// Pass search base as argument for group membership searches.
.groupSearchBase("ou=groups")
// Configures base LDAP path context source
.contextSource().url("ldap://localhost:10389/dc=javachinna,dc=com")
// DN of the user who will bind to the LDAP server to perform the search
.managerDn("uid=admin,ou=system")
// Password of the user who will bind to the LDAP server to perform the search
.managerPassword("secret").and()
// Configures LDAP compare operation of the user password to authenticate
.passwordCompare().passwordEncoder(new LdapShaPasswordEncoder())
// Specifies the attribute in the directory which contains the user password.
// Defaults to "userPassword".
.passwordAttribute("userPassword").and()
// Populates the user roles by LDAP user name from database
.ldapAuthoritiesPopulator(ldapUserAuthoritiesPopulator);
// Basic / JWT authentication
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// Disable CSRF
httpSecurity.csrf().disable()
// Only admin can perform HTTP delete operation
.authorizeRequests().antMatchers(HttpMethod.DELETE).hasRole(Role.ADMIN)
// any authenticated user can perform all other operations
.antMatchers("/products/**").hasAnyRole(Role.ADMIN, Role.USER).and().httpBasic()
// Permit all other request without authentication
.and().authorizeRequests().anyRequest().permitAll()
// Reject every unauthenticated request and send error code 401.
.and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
// We don't need sessions to be created.
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
JwtRequestFilter
会在请求头中寻找令牌。
如果找到令牌,那么它将验证令牌并在 Spring Security Context 中手动设置身份验证。
否则,记录警告并继续进行下一次身份验证
LDAP 身份验证提供程序将使用 LDAP 服务器验证用户凭据。
如果认证成功,那么它会尝试从数据库中通过用户名获取用户权限。如果找到权限,则将其分配给用户。否则,将分配默认用户角色并完成身份验证过程。
否则,它将继续进行下一个身份验证。
基本身份验证提供程序将使用 UserDetailsService
实现通过数据库验证用户凭据。
如果认证成功,则认证主体将在安全上下文中设置为已配置的权限,过程完成。
否则,身份验证失败,过程完成。
如果在数据库中找不到给定 LDAP 用户名的用户权限,则修改此类以分配默认用户角色。
package com.javachinna.config;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.stereotype.Component;
import com.javachinna.model.Role;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequiredArgsConstructor
@Component
public class LdapUserAuthoritiesPopulator implements LdapAuthoritiesPopulator {
private final UserDetailsService userDetailsService;
@Override
public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
Collection<? extends GrantedAuthority> authorities = new HashSet<>();
try {
authorities = userDetailsService.loadUserByUsername(username).getAuthorities();
} catch (Exception e) {
log.warn("Unable to fetch the user authorities from the database. Hence, assigning default user role");
authorities = Arrays.asList(new SimpleGrantedAuthority(Role.ROLE_USER));
}
return authorities;
}
}
我们需要将 MULTI_AUTH
配置文件添加到以下 JWT 过滤器和控制器中,以便为该配置文件启用它们。
@Component
@Profile({Profiles.JWT_AUTH, Profiles.MULTI_AUTH})
@RequiredArgsConstructor
public class JwtRequestFilter extends OncePerRequestFilter {
@Profile({Profiles.JWT_AUTH, Profiles.MULTI_AUTH})
@RestController
@CrossOrigin
@RequiredArgsConstructor
public class JwtAuthenticationController {
您可以使用 mvn spring-boot:run -Dspring-boot.run.profiles=multiauth
运行该应用程序,然后在浏览器中点击 URL http://localhost:8080/swagger-ui.html。您应该能够使用上述任何身份验证来执行服务。
和往常一样,你可以从下面的 Github 获取源代码
https://github.com/JavaChinna/spring-boot-rest-multi-auth
这就是所有的人!在本文中,您学习了如何在单个配置文件中为 Spring Boot RESTful 服务配置多个身份验证提供程序。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.javachinna.com/spring-security-multiple-authentication-providers/
内容来源于网络,如有侵权,请联系作者删除!