Я'м с использованием Spring безопасности для защиты Struts2 веб-приложения. Из-за ограничений проекта, Я'м с использованием Spring безопасности 2.06.
Моя команда создала пользовательский API руководство пользователя для проверки подлинности пользователя после принятия в параметры username и пароль, и возвращает пользовательский объект, содержащий список ролей и другие атрибуты, такие как электронная почта, имя и т. д.
В моем понимании, типичный весенний использования безопасности использует UserDetailsService по умолчанию для извлечения объекта UserDetails; этот объект будет содержать (среди прочего) в поле пароль, который будет использоваться платформой для проверки подлинности пользователя.
В моем случае, я хочу, чтобы наша пользовательский API аутентификации, а затем вернуться в пользовательский объект, содержащий UserDetails роль и другие атрибуты (электронная почта и т. д.).
После некоторых исследований, я выяснил, что я могу сделать это с помощью пользовательской реализации AuthenticationProvider. У меня также есть пользовательские реализации UserDetailsService и UserDetails.
Моя проблема заключается в том, что я Дон't действительно понять, что я'м должен быть возвращение в CustomAuthenticationProvider. Я могу использовать мои пользовательские UserDetailsService объект здесь? Что еще нужно? К сожалению, я'м не понимаю.
CustomAuthenticationProvider:
public class CustomAuthenticationProvider implements AuthenticationProvider {
private Logger logger = Logger.getLogger(CustomAuthenticationProvider.class);
private UserDetailsService userDetailsService; //what am i supposed to do with this?
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
String username = String.valueOf(auth.getPrincipal());
String password = String.valueOf(auth.getCredentials());
logger.info("username:" + username);
logger.info("password:" + password);
/* what should happen here? */
return null; //what do i return?
}
@Override
public boolean supports(Class aClass) {
return true; //To indicate that this authenticationprovider can handle the auth request. since there's currently only one way of logging in, always return true
}
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
applicationContext-security.xml:
<beans:bean id="customUserDetailsService" scope="prototype" class="com.test.testconsole.security.CustomUserDetailsService"/>
<beans:bean id="customAuthenticationProvider" class="com.test.testconsole.security.CustomAuthenticationProvider">
<custom-authentication-provider />
<beans:property name="userDetailsService" ref="customUserDetailsService" />
</beans:bean>
Подводя итог, это то, что мне нужно:
//весна безопасности получить имя пользователя Проверка подлинности проверка подлинности = SecurityContextHolder.метода getcontext().getAuthentication(); имя пользователя = авт.метод getname(); //войти в систему имя пользователя логгер.информация (на"Имя пользователя: на " + имя пользователя);
//весна безопасности вам роль пользователей GrantedAuthority[] власти = авт.getAuthorities(); userRole = власти[0].getAuthority(); логгер.информация (на"роль пользователя: на " + userRole);
Я надеюсь, что это имеет смысл. Любая помощь или указатели будут оценены!
Спасибо!
Обновление:
Я'вэ достигли определенного прогресса, я думаю.
У меня есть пользовательские проверки подлинности объекта, реализующего интерфейс проверки подлинности:
public class CustomAuthentication implements Authentication {
String name;
GrantedAuthority[] authorities;
Object credentials;
Object details;
Object principal;
boolean authenticated;
public CustomAuthentication(String name, GrantedAuthority[] authorities, Object credentials, Object details, Object principal, boolean
authenticated){
this.name=name;
this.authorities=authorities;
this.details=details;
this.principal=principal;
this.authenticated=authenticated;
}
@Override
public GrantedAuthority[] getAuthorities() {
return new GrantedAuthority[0]; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Object getCredentials() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Object getDetails() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Object getPrincipal() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean isAuthenticated() {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public String getName() {
return null;
}
}
и обновил свой класс CustomerAuthenticationProvider:
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
String username = String.valueOf(auth.getPrincipal());
String password = String.valueOf(auth.getCredentials());
logger.info("username:" + username);
logger.info("password:" + password);
//no actual validation done at this time
GrantedAuthority[] authorities = new GrantedAuthorityImpl[1];
authorities[0] = new GrantedAuthorityImpl("ROLE_USER");
CustomAuthentication customAuthentication = new CustomAuthentication("TestMerchant",authorities,"details",username,password,true);
return customAuthentication;
//return new UsernamePasswordAuthenticationToken(username,password,authorities);
}
Это работает, если я возвращать объект UsernamePasswordAuthenticationToken, но если я попытаюсь вернуть CustomAuthentication, я получаю следующую ошибку:
java.lang.ClassCastException: com.test.testconsole.security.CustomAuthentication cannot be cast to org.springframework.security.providers.UsernamePasswordAuthenticationToken
at com.test.testconsole.security.CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:27)
at org.springframework.security.providers.ProviderManager.doAuthentication(ProviderManager.java:188)
at org.springframework.security.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:46)
at org.springframework.security.intercept.AbstractSecurityInterceptor.authenticateIfRequired(AbstractSecurityInterceptor.java:319)
at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:258)
at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:106)
at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:116)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.basicauth.BasicProcessingFilter.doFilterHttp(BasicProcessingFilter.java:174)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:278)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:536)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:915)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:539)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:405)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Это's, как что-то ожидает не просто любой предмет подлинности, но конкретная реализация его - UsernamePasswordAuthenticationToken. Это заставляет меня думать, что я, возможно, отсутствует еще один особый компонент .. может фильтр?
Если вы реализуете свой собственный AuthenticationProvider
, вы Дон't имеет для успешной реализации UserDetailsServiceесли вы Don'т хотите.
UserDetailsService только обеспечивает стандартный DAO для загрузки информации пользователя и некоторые другие классы в рамках реализуемых ею пользоваться.
Как правило, для проверки подлинности с помощью имени пользователя и пароля, вы бы инстанцировать DaoAuthenticationProvider
и ввести этот UserDetailsService`. Что еще может быть лучшим подходом. Если вы реализуете свой собственный провайдер, вы берете на себя ответственность убедиться, что пользователь предоставил верный пароль и так далее. Однако, в некоторых случаях это простой подход.
Чтобы ответить на ваши "что должно произойти здесь?" и комментарий в ваш код, это будет что-то вроде
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
String username = String.valueOf(auth.getPrincipal());
String password = String.valueOf(auth.getCredentials());
logger.info("username:" + username);
logger.info("password:" + password); // Don't log passwords in real app
// 1. Use the username to load the data for the user, including authorities and password.
YourUser user = ....
// 2. Check the passwords match (should use a hashed password here).
if (!user.getPassword().equals(password)) {
throw new BadCredentialsException("Bad Credentials");
}
// 3. Preferably clear the password in the user object before storing in authentication object
user.clearPassword();
// 4. Return an authenticated token, containing user data and authorities
return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()) ;
}
Объект пользователя, то можно будет попасть с помощью
Authentication.getPrincipal()
способ, и вы можете получить доступ к дополнительным свойствам (электронная почта и т. д.), бросая его на вашу пользовательскую реализацию пользователей.
Как загрузить пользовательские данные до вас. Всю весну заботится о безопасности здесь является AuthenticationProvider интерфейс.
Вы должны также хранить хэши паролей и проверки пароля используя тот же алгоритм, а не просто проверить равенство.
спасибо за размещение этого лука!
Спас меня от еще повреждения головного мозга.
Единственное, обратите внимание, я столкнулся, для тех, кто заботится:
Мои настройки:
При использовании с благодарностью упрощенный/шикарная Люк подход предполагает, не реализация пользовательского UserDetails (или UserDetailsService) объект и с помощью собственных пользователей домен объект, на который не распространяется ничего особенного, вы должны принять дополнительный шаг, если вы используете "и ТРЦ" и настраиваемые теги с весны безопасности (на страницах курса):
Когда вы создаете экземпляр базового, нестандартная UsernamePasswordAuthenticationToken, вы должны передать его экземпляр чего-то, что снова расширяет Основные,, если вы хотите, чтобы ваш весенний безопасности пользовательских тегов Гапа в работе. Я сделал что-то вроде этого, чтобы держать его как можно более простым (ссылка моего пользователя домена ценности объекта, где полезное/нужное):
def principalUser = new org.springframework.security.core.userdetails.User(user.username, user.password, user.enabled, !user.accountExpired, !user.passwordExpired,!user.accountLocked, authorities)
def token = new UsernamePasswordAuthenticationToken(principalUser, presentedPassword, authorities)
Это должно удовлетворять условиям испытания для в Grails.Плагины.springsecurity.SecurityTagLib.determineSource() Итак, вы знаете, ваши страницы, которые используют в <сек:loggedInUserInfo>
будет на самом деле сделать:
if (principal.metaClass.respondsTo(principal, 'getDomainClass')) {
return principal.domainClass
}
В противном случае, если вы инстанцировать UsernamePasswordAuthenticationToken с пользователем предметной области (Луки показать на своем примере), что бирки обеспеченностью Либ способ (determineSource()) будет просто сделать это'ы уровень лучше и вернуть (мета) значение орг.codehaus.груви.граалей.общин.DefaultGrailsDomainClass и вы'll получают ошибку, когда тег ищет переменную пользователей с указанием:
Error executing tag <sec:ifLoggedIn>: Error executing tag <sec:loggedInUserInfo>: No such property: username for class: org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
Короткое повторной реализации/создание подклассов весна-безопасности-ядро плагина taglibs в мой файл Grails проекта, там's просто нет возможности как использовать taglibs и использовать свой собственный домен пользователей класса, чтобы инстанцировать маркер передается от фильтра к вашему провайдеру.
Опять же, одна дополнительная строка кода-это очень маленькая цена, чтобы заплатить :)