gpt4 book ai didi

java - 使用 java config 在单个应用程序中使用多种身份验证机制

转载 作者:IT老高 更新时间:2023-10-28 20:37:08 30 4
gpt4 key购买 nike

目前,我的应用程序中有一个单一的身份验证机制,即使用 LDAP 进行身份验证和授权。我的安全配置如下所示

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.httpBasic();
}

@Configuration
protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {

@Value("${ldap-${env}.manager.dn}")
private String managerDn;

@Value("${ldap-${env}.manager.pass}")
private String managerPass;

@Value("${ldap-${env}.server.url}")
private String url;

@Value("${ldap.password.attribute:userPassword}")
private String passwordAttr;

@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication().userDnPatterns("uid={0},ou=people").groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})").userSearchBase("ou=people").userSearchFilter("(uid={0})")
.userDetailsContextMapper(new CustomLdapPersonContextMapper())
// .passwordCompare()
// .passwordAttribute(passwordAttr)
// .passwordEncoder(new PlaintextPasswordEncoder())
// .and()
.contextSource().managerDn(managerDn).managerPassword(managerPass).url(url);
}
}
}

在某些情况下,用户可能会带着一个 session token 进入,该 token 可以从 session key 服务器进行身份验证,并且有效 token 返回一个用户名,然后可以使用该用户名从 LDAP 为该用户加载授权信息。因此,我的第二个身份验证机制应该首先发生,如果 HTTP header 中存在 session token ,它应该执行 token 身份验证,然后执行 ldap 查找,如果不存在 session token ,它应该只属于当前身份验证机制。如何添加第二层身份验证。

最佳答案

在使用纯 java 配置时,我花了很多时间来研究 spring-security。有几个步骤可以让这个工作。应该是这样的。基本流程如下:

  • 创建自定义过滤器以检查特定授权信息的请求

  • 每个过滤器都返回 null(如果没有找到该类型的授权),或者自定义 AbstractAuthenticationToken

  • 如果过滤器返回一个 token ,每个 AuthenticationProvider 的 support(class) 方法将被调用,该 token 返回 true|false 如果它应该尝试身份验证

  • attemptAuthentication 然后将在支持 token 的 AuthenticationProvider 上调用。在这里,您可以执行任何服务调用来验证用户。然后,您可以抛出 LoginException 或调用 authentication.setAuthenticated(true) 并返回 token 以进行成功的身份验证。

我一直在使用此设置支持各种身份验证方法(签名请求、用户名/密码、oauth 等),并且效果很好。

您还可以将 AuthenticationSuccessHandler 和 AuthenticationFailuersHandler 传递给自定义安全过滤器,以提供自定义重定向策略和故障处理。

还要确保在过滤器的构造函数中设置 ant 匹配器,以控制过滤器应用的 url 模式。例如,ldap 请求过滤器可能需要检查任何请求“/*”,而用户名/密码过滤器可以只检查 POST 到/login 或类似的东西。

示例代码:

1) 为您想要支持的每种身份验证类型创建自定义 AuthenticationToken

public class LDAPAuthorizationToken extends AbstractAuthenticationToken {
private String token;

public LDAPAuthorizationToken( String token ) {
super( null );
this.token = token;
}

public Object getCredentials() {
return token;
}

public Object getPrincipal() {
return null;
}
}

public class OTPAuthorizationToken extends UsernamePasswordAuthenticationToken {
private String otp;

public OTPAuthorizationToken( String username, String password, String otp ) {
super( username, password );
this.otp = otp;
}

public String getOTP() {
return otp;
}
}

2) 为每种类型创建自定义安全过滤器

public class LDAPAuthorizationFilter extends AbstractAuthenticationProcessingFilter {
@Autowired
private UserDetailsService userDetailsService;

public LDAPAuthorizationFilter() {
super( "/*" ); // allow any request to contain an authorization header
}

public Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response ) throws AuthenticationException
{

if ( request.getHeader( "Authorization" ) == null ) {
return null; // no header found, continue on to other security filters
}

// return a new authentication token to be processed by the authentication provider
return new LDAPAuthorizationToken( request.getHeader( "Authorization" ) );
}
}

public class OTPAuthorizationFilter extends AbstractAuthenticationProcessingFilter {
@Autowired
private UserDetailsService userDetailsService;

public OTPAuthorizationFilter() {
super( "/otp_login" );
}

public Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response ) throws AuthenticationException
{

if ( request.getParameter( "username" ) == null || request.getParameter( "password" ) == null || request.getParameter( "otp" ) == null ) {
return null;
}

// return a new authentication token to be processed by the authentication provider
return new OTPAuthorizationToken( request.getParameter( "username" ), request.getParameter( "password" ), request.getParameter( "otp" ) );
}
}

3) 创建自定义 AuthenticationProviders

public class LDAPAuthenticationProvider implements AuthenticationProvider {

@Autowired
private MyAuthenticationService sampleService;

@Override
public Authentication authenticate( Authentication authentication ) throws AuthenticationException {
LDAPAuthorizationToken auth = (LDAPAuthorizationToken)authentication;

String username = sampleService.verifyToken( auth.getCredentials() );
if ( username == null ) {
throw new LoginException( "Invalid Token" );
}

auth.setAuthenticated( true );

return auth;
}

@Override
public boolean supports( Class<?> authentication ) {
if ( authentication.isAssignableFrom( LDAPAuthorizationToken.class ) ) {
return true;
}
return false;
}
}

public class OTPAuthenticationProvider implements AuthenticationProvider {

@Autowired
private MyAuthenticationService sampleService;

@Override
public Authentication authenticate( Authentication authentication ) throws AuthenticationException {
OTPAuthorizationToken auth = (OTPAuthorizationToken)authentication;

String error = sampleService.loginWithOTP( auth.getPrincipal(), auth.getCredentials(), auth.getOTP() );
if ( error != null ) {
throw new LoginException( error );
}

auth.setAuthenticated( true );

return auth;
}

@Override
public boolean supports( Class<?> authentication ) {
if ( authentication.isAssignableFrom( OTPAuthorizationToken.class ) ) {
return true;
}
return false;
}
}

4) 配置spring security

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure( HttpSecurity http ) throws Exception {
// configure filters
http.addFilterBefore( new LDAPAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class );
http.addFilterBefore( new OTPAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class );

// configure authentication providers
http.authenticationProvider( new LDAPAuthenticationProvider() );
http.authenticationProvider( new OTPAuthenticationProvider() );

// disable csrf
http.csrf().disable();

// setup security
http.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and().httpBasic();
}
}

希望有帮助!

关于java - 使用 java config 在单个应用程序中使用多种身份验证机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25794680/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com