ログイン試行を制限するための構成または使用可能なモジュールがSpringSecurityにありますか(理想的には、後続の失敗した試行間の待機時間を増やしたい)?そうでない場合は、APIのどの部分をこれに使用する必要がありますか?
DB内のカウント/時間を更新するAuthenticationFailureHandlerを実装します。とにかく攻撃者がCookieを送信することはないので、セッションの使用は期待していません。
Spring 4.2以降 アノテーションベースのイベントリスナー が利用可能です:
@Component
public class AuthenticationEventListener {
@EventListener
public void authenticationFailed(AuthenticationFailureBadCredentialsEvent event) {
String username = (String) event.getAuthentication().getPrincipal();
// update the failed login count for the user
// ...
}
}
http://forum.springsource.org/showthread.php?108640-Login-attempts-Spring-security でRob Winchが提案したように、私はDaoAuthenticationProvider
をサブクラス化しました(これも可能です)失敗したログインの数を制限するために、Riteshが提案するアスペクトを使用して実行されていますが、前提条件をアサートすることもできます。
public class LimitingDaoAuthenticationProvider extends DaoAuthenticationProvider {
@Autowired
private UserService userService;
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// Could assert pre-conditions here, e.g. rate-limiting
// and throw a custom AuthenticationException if necessary
try {
return super.authenticate(authentication);
} catch (BadCredentialsException e) {
// Will throw a custom exception if too many failed logins have occurred
userService.recordLoginFailure(authentication);
throw e;
}
}
}
Spring config XMLで、次のBeanを参照するだけです。
<beans id="authenticationProvider"
class="mypackage.LimitingDaoAuthenticationProvider"
p:userDetailsService-ref="userDetailsService"
p:passwordEncoder-ref="passwordEncoder"/>
<security:authentication-manager>
<security:authentication-provider ref="authenticationProvider"/>
</security:authentication-manager>
AuthenticationException
のauthentication
またはextraInformation
プロパティへのアクセスに依存するソリューション(AuthenticationFailureHandler
の実装など)は、おそらく使用すべきではないと思います。プロパティは非推奨になりました(少なくともSpring Security 3.1では)。
最近、JMXを使用してログインの失敗を監視するための同様の機能を実装しました。質問に対する私の回答のコードを参照してください NotificationPublisherAwareなしでSpringを使用してJMX通知を公開する 。認証プロバイダーの認証方法の側面は、MBeanを更新し、通知リスナー(その質問には示されていないコード)と連携して、ユーザーとIPをブロックし、アラートEメールを送信し、障害がしきい値を超えた場合にログインを一時停止します。
編集
質問への私の回答と同様 春のセキュリティ3:認証に関する情報をデータベースに保存する 、認証失敗イベントをキャプチャし(ハンドラーをカスタマイズするのではなく)、データベースに情報を保存すると思いますまた、機能し、コードも分離されたままになります。
ApplicationListener <AuthenticationFailureBadCredentialsEvent>を実装するサービスを使用して、DBのレコードを更新することもできます。
春のアプリケーションイベントを参照してください。
これが私の実装です。助けてください。
AbstractUserDetailsAuthenticationProvider
を参照)最後に、DaoAuthenticationProviderを拡張し、内部のロジックを統合します。
@Component("authenticationProvider")
public class YourAuthenticationProvider extends DaoAuthenticationProvider {
@Autowired
UserAttemptsDao userAttemptsDao;
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
try {
Authentication auth = super.authenticate(authentication);
//if corrent password, reset the user_attempts
userAttemptsDao.resetFailAttempts(authentication.getName());
return auth;
} catch (BadCredentialsException e) {
//invalid login, update user_attempts, set attempts+1
userAttemptsDao.updateFailAttempts(authentication.getName());
throw e;
}
}
}
完全なソースコードと実装については、これを参照してください 春のセキュリティ制限ログイン試行の例 、
カスタムイベントリスナーを作成する
@Component("authenticationEventListner")
public class AuthenticationEventListener
implements AuthenticationEventPublisher
{
@Autowired
UserAttemptsServices userAttemptsService;
@Autowired
UserService userService;
private static final int MAX_ATTEMPTS = 3;
static final Logger logger = LoggerFactory.getLogger(AuthenticationEventListener.class);
@Override
public void publishAuthenticationSuccess(Authentication authentication) {
logger.info("User has been logged in Successfully :" +authentication.getName());
userAttemptsService.resetFailAttempts(authentication.getName());
}
@Override
public void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {
logger.info("User Login failed :" +authentication.getName());
String username = authentication.getName().toString();
UserAttempts userAttempt = userAttemptsService.getUserAttempts(username);
User userExists = userService.findBySSO(username);
int attempts = 0;
String error = "";
String lastAttempted = "";
if (userAttempt == null) {
if(userExists !=null ){
userAttemptsService.insertFailAttempts(username); }
} else {
attempts = userAttempt.getAttempts();
lastAttempted = userAttempt.getLastModified();
userAttemptsService.updateFailAttempts(username, attempts);
if (attempts + 1 >= MAX_ATTEMPTS) {
error = "User account is locked! <br>Username : "
+ username+ "<br>Last Attempted on : " + lastAttempted;
throw new LockedException(error);
}
}
throw new BadCredentialsException("Invalid User Name and Password");
}
}
3.セキュリティ構成
1) @Autowired
@Qualifier("authenticationEventListner")
AuthenticationEventListener authenticationEventListner;
2) @Bean
public AuthenticationEventPublisher authenticationListener() {
return new AuthenticationEventListener();
}
3) @Autowired
public void
configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
//configuring custom user details service
auth.authenticationProvider(authenticationProvider);
// configuring login success and failure event listener
auth.authenticationEventPublisher(authenticationEventListner);
}