具有不同UsernamePasswordAuthToken的多个AuthenticationProvider可以对不同的登录表单进行身份验证,而无需回退身份验证 [英] Multiple AuthenticationProvider with different UsernamePasswordAuthToken to authenticate different login forms without fallback authentication
问题描述
在使用Spring Security时,我研究了stackoverflow中一个有趣的线程,但需要针对不同的身份验证提供程序对两组用户进行身份验证, LDAP
和客户反对DATABASE
. Thread提出了一种公认的解决方案,即具有一个带有单选按钮的登录表单,以区分员工和客户,并具有自定义身份验证过滤器,该过滤器根据userType区分登录请求并设置不同的authenticationToken( customerAuthToken / employeeAuthToken ),然后进行身份验证请求.将有两个AuthenticationProvider
实现,并且身份验证是通过支持令牌来完成和确定的.
通过这种方式,线程能够提供有趣的解决方案,从而避免默认情况下Spring Security提供的回退身份验证.
While working with spring security I had a look at interesting thread in stackoverflow, there it was requirement to have authenticating two set of users against different authentication provider say employees against LDAP
and customer against DATABASE
. Thread came up with accepted solution to have a single login form with a radio button to distinguish employee from customer and to have custom authentication filter which differentiate login request based on userType and sets different authenticationToken(customerAuthToken/employeeAuthToken) and request is proceeded for authentication. There will be two AuthenticationProvider
implementation and authentication is done and decided by supporting token.
In this way thread was able to provide interesting solution to avoid fallback authentication which spring security provides by default.
看看线程配置Spring Security 3 .x具有多个入口点
因为答案完全在xml配置中.我只是想让解决方案在Java配置中可用.我将在答复中发布.
Since answer is completely in xml configuration. I just wanted to have the solution be available in java configuration. I will be posting that in answer.
现在我的问题,随着春季版本的发展,除了我的答案以外,是否有可能通过任何新功能/最低配置拥有相同的功能?
Now my question, with evolution of spring version, is it possible to have the same functionality by any new features/ minimal configurations apart from my answer?
推荐答案
Since this thread given complete information, i am just posting codes for java configuration reference.
我在这里假设以下事情
1.用户和管理员为两组用户.
2.为简单起见,在两者中都使用内存身份验证.
-如果userType为用户",则仅用户凭据应起作用.
-如果userType为Admin,则仅管理员凭据应起作用.
-并且应该能够向不同的权限提供相同的应用程序界面.
Here i am assuming following things
1. User's and Admin's as two set of users.
2. For simplicity using in memory authentication for both.
- If userType is User only user credential should work.
- If userType is Admin only admin credential should work.
- And should be able to provide same application interface with different authorities.
CustomAuthenticationFilter
And the codes
You can download working code from my github repository
CustomAuthenticationFilter
@Component
public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter
{
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException
{
UsernamePasswordAuthenticationToken authToken = null;
if ("user".equals(request.getParameter("userType")))
{
authToken = new UserUsernamePasswordAuthenticationToken(request.getParameter("userName"), request.getParameter("password"));
}
else
{
authToken = new AdminUsernamePasswordAuthenticationToken(request.getParameter("userName"), request.getParameter("password"));
}
setDetails(request, authToken);
return super.getAuthenticationManager().authenticate(authToken);
}
}
CustomAuthentictionTokens
public class AdminUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken
{
public AdminUsernamePasswordAuthenticationToken(Object principal, Object credentials)
{
super(principal, credentials);
}
public AdminUsernamePasswordAuthenticationToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities)
{
super(principal, credentials, authorities);
}
}
public class UserUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken
{
public UserUsernamePasswordAuthenticationToken(Object principal, Object credentials)
{
super(principal, credentials);
}
public UserUsernamePasswordAuthenticationToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities)
{
super(principal, credentials, authorities);
}}
CustomAuthentictionProvider - For Admin
@Component
public class AdminCustomAuthenticationProvider implements AuthenticationProvider
{
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
String username = authentication.getName();
String password = authentication.getCredentials().toString();
if (username.equals("admin") && password.equals("admin@123#"))
{
List<GrantedAuthority> authorityList = new ArrayList<>();
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_ADMIN");
authorityList.add(authority);
return new UserUsernamePasswordAuthenticationToken(username, password, authorityList);
}
return null;
}
@Override
public boolean supports(Class<?> authentication)
{
return authentication.equals(AdminUsernamePasswordAuthenticationToken.class);
}
}
CustomAuthentictionProvider - For User
@Component
public class UserCustomAuthenticationProvider implements AuthenticationProvider
{
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
String username = authentication.getName();
String password = authentication.getCredentials().toString();
if (username.equals("user") && password.equals("user@123#"))
{
List<GrantedAuthority> authorityList = new ArrayList<>();
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
authorityList.add(authority);
return new UserUsernamePasswordAuthenticationToken(username, password, authorityList);
}
return null;
}
@Override
public boolean supports(Class<?> authentication)
{
return authentication.equals(UserUsernamePasswordAuthenticationToken.class);
}
}
CustomHandlers required for CustomFilter
@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler
{
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException
{
response.sendRedirect(request.getContextPath() + "/login?error=true");
}
}
@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler
{
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException
{
HttpSession session = request.getSession();
if (session != null)
{
session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
}
response.sendRedirect(request.getContextPath() + "/app/user/dashboard");
}
}
最后是 SpringSecurityConfiguration
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{
@Autowired
DataSource dataSource;
@Autowired
private AdminCustomAuthenticationProvider adminCustomAuthenticationProvider;
@Autowired
private UserCustomAuthenticationProvider userCustomAuthenticationProvider;
@Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.authenticationProvider(adminCustomAuthenticationProvider);
auth.authenticationProvider(userCustomAuthenticationProvider);
}
@Bean
public MyAuthenticationFilter myAuthenticationFilter() throws Exception
{
MyAuthenticationFilter authenticationFilter = new MyAuthenticationFilter();
authenticationFilter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
authenticationFilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler);
authenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
authenticationFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationFilter;
}
@Override
protected void configure(final HttpSecurity http) throws Exception
{
http
.addFilterBefore(myAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.csrf().disable()
.authorizeRequests()
.antMatchers("/resources/**", "/", "/login")
.permitAll()
.antMatchers("/config/*", "/app/admin/*")
.hasRole("ADMIN")
.antMatchers("/app/user/*")
.hasAnyRole("ADMIN", "USER")
.antMatchers("/api/**")
.hasRole("APIUSER")
.and().exceptionHandling()
.accessDeniedPage("/403")
.and().logout()
.logoutSuccessHandler(new CustomLogoutSuccessHandler())
.invalidateHttpSession(true);
http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired=true");
}
}
希望它将有助于您了解如何配置没有后备身份验证的多重身份验证.
Hope it will help to understand configuring multiple authentication without fallback authentication.
这篇关于具有不同UsernamePasswordAuthToken的多个AuthenticationProvider可以对不同的登录表单进行身份验证,而无需回退身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!