ade*_*ood 24 java spring-security spring-security-ldap
目前我的应用程序中有一个身份验证机制,即使用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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在某些情况下,用户可能会使用会话令牌进入会话令牌,该会话令牌可以从会话密钥服务器进行身份验证,并且有效令牌会返回用户名,然后可以使用该用户名从LDAP为该用户加载身份验证信息.所以我的第二个身份验证机制应该首先发生,如果http头中存在会话令牌,它应该执行令牌身份验证然后执行ldap查找,如果没有会话令牌,它应该属于当前的身份验证机制.如何添加第二层身份验证.
Mat*_*ean 51
在使用纯java配置时,我花了很长时间围绕spring-security.让这个工作有一些步骤.它应该是这些方面的东西.基本流程如下:
创建自定义筛选器以检查特定授权信息的请求
每个过滤器返回null(如果未找到该类型的授权)或自定义AbstractAuthenticationToken
如果过滤器返回一个标记,那么将调用每个AuthenticationProvider的支持(类)方法,如果该标记应该尝试认证,则返回true | false
然后将在支持令牌的AuthenticationProvider上调用attemptAuthentication.在这里,您可以执行任何服务调用来验证用户身份.然后,您可以抛出LoginException或调用authentication.setAuthenticated(true)并返回令牌以进行成功的身份验证.
我一直在使用此设置支持各种身份验证方法(签名请求,用户名/密码,oauth等),并且它运行良好.
您还可以将AuthenticationSuccessHandler和AuthenticationFailuersHandler传递给自定义安全筛选器,以提供自定义重定向策略和故障处理.
还要确保在过滤器的构造函数中设置蚂蚁匹配器,以控制过滤器应用的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;
}
}
Run Code Online (Sandbox Code Playgroud)
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" ) );
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
4)配置弹簧安全性
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();
}
}
Run Code Online (Sandbox Code Playgroud)
希望有所帮助!
Bri*_*ace 13
另外,选择添加第二个身份验证提供者:只需指定在一个又一个AuthenticationManagerBuilder.因为@EnableWebSecurity注释本身是注释的,EnableGlobalAuthentication所以可以配置全局实例AuthenticationManagerBuilder.(有关详细信息,请参阅javadoc.)
例如,这里我们有一个LDAP身份验证提供程序以及一个内存(硬编码)身份验证提供程序(这是我们在开发过程中要让本地用户进行测试):
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${user.role}")
private String userRole; // i.e. ROLE_APP_USER
@Value("${include.test.users}")
private boolean includeTestUsers;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**/js/**").permitAll()
.antMatchers("/**/images/**").permitAll()
.antMatchers("/**/favicon.ico").permitAll()
.antMatchers("/**/css/**").permitAll()
.antMatchers("/**/fonts/**").permitAll()
.antMatchers("/**").hasAnyRole(userRole)
.and().formLogin().loginPage("/login").permitAll().and().logout().permitAll();
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, LdapContextSource contextSource) throws Exception {
auth.ldapAuthentication()
.userSearchBase("OU=Users OU")
.userSearchFilter("sAMAccountName={0}")
.groupSearchBase("OU=Groups OU")
.groupSearchFilter("member={0}")
.contextSource(contextSource);
if (includeTestUsers) {
auth.inMemoryAuthentication().withUser("user").password("u").authorities(userRole);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
30905 次 |
| 最近记录: |