Spring -security: авторизация без аутентификации
Я пытаюсь интегрировать Spring Безопасность в своем веб-приложении. Кажется довольно легко сделать, пока вы интегрируете весь процесс аутентификации и авторизации.
Однако, как аутентификация, так и авторизация кажутся настолько связанными, что для меня очень много времени, чтобы понять, как я могу разделить эти процессы и получить аутентификацию независимо от авторизации.
Процесс аутентификации является внешним по отношению к нашей системе (на основе единого входа), и это не может быть изменено. Тем не менее, как только пользователь преуспеет в этом процессе, он загружается в сеанс, включая роли.
То, что мы пытаемся достичь, - это использовать эту информацию для процесса авторизации Spring Security, чтобы заставить его получить роли из пользовательского сеанса, а не собирать его через аутентификацию - провайдера.
Есть ли способ достичь этого?
Ответы
Ответ 1
Если ваша аутентификация уже выполнена с использованием службы единого входа, вы должны использовать один из spring security фильтры предварительной аутентификации. Затем вы можете указать службу UserDetails (возможно, пользовательскую), которая будет использовать предварительно аутентифицированный пользовательский принцип для заполнения
GrantedAuthority
SpringSecurity включает в себя несколько фильтров предварительной аутентификации, включая J2eePreAuthenticatedProcessingFilter и RequestHeaderPreAuthenticatedProcessingFilter. Если вы не можете найти тот, который работает для вас, это также возможно, а не так сложно писать самостоятельно, если вы знаете, где в запросе ваша реализация единого входа заполняет данные. (Это зависит от реализации курса.)
Просто реализуйте интерфейс Filter и выполните что-то подобное в методе doFilter:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// principal is set in here as a header or parameter. you need to find out
// what it named to extract it
HttpServletRequest req = (HttpServletRequest) request;
if (SecurityContextHolder.getContext().getAuthentication() == null) {
// in here, get your principal, and populate the auth object with
// the right authorities
Authentication auth = doAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
Ответ 2
Да, это возможно. Spring Безопасность (как и большинство остальных Spring) управляется интерфейсом, поэтому вы можете выборочно подключать свои собственные реализации для разных частей фреймворка.
Обновление: Spring механизмы авторизации и аутентификации работают вместе - механизм аутентификации будет аутентифицировать пользователя и вставить различные экземпляры GrantedAuthority
в контексте безопасности. Затем они будут проверяться механизмом авторизации, чтобы разрешить/запретить определенные операции.
Используйте nont-ответ для получения информации о том, как использовать существующую аутентификацию. Информация о том, как вы получаете информацию из своего сеанса (например, роли), будет зависеть, конечно, от конкретной настройки. Но если вы введете экземпляры GrantedAuthority
, полученные из ролей, предварительно заполненных в вашем сеансе вашей системой единого входа, вы сможете использовать их в своей логике авторизации.
Из справочной документации (слегка отредактированной с моим акцентом):
Вы можете (и многие пользователи) писать их собственные фильтры или контроллеры MVC для обеспечения совместимости с системы аутентификации, которые не являются на основе Spring Безопасность. Например, вы можете использовать Container Managed Аутентификация, которая пользователя из ThreadLocal
или JNDI
. Или вы можете работать на компания, у которой есть наследство системы аутентификации, которая является корпоративный "стандарт", над которым вы имеют небольшой контроль. В таком ситуации довольно легко получить Spring Безопасность для работы, и все еще предоставить возможности авторизации. Все, что вам нужно сделать, это написать фильтр (или эквивалент), который читает сторонняя информация пользователя из местоположение, постройте SpringСпециально для безопасности Authentication
объекта и поместить его на SecurityContextHolder
. Это довольно легко для этого, и это полностью поддерживаемый интеграционный подход.
Ответ 3
Сервер, который обрабатывает аутентификацию, должен перенаправить пользователя к приложению, передав ему какой-то ключ (токен в CAS SSO). Затем приложение использует ключ для запроса на сервер аутентификации имени пользователя и связанных с ним ролей. С помощью этой информации создайте контекст безопасности, который передается диспетчеру авторизации. Это очень упрощенная версия рабочего процесса входа в систему SSO.
Взгляните на CAS SSO и Архитектура CAS 2.
Скажите мне, если вам нужна дополнительная информация.
Ответ 4
у нас было такое же требование, когда нам приходилось использовать spring для обеспечения только для авторизации. Мы использовали Siteminder для аутентификации. Более подробную информацию о том, как использовать авторизационную часть spring безопасности, а не аутентификацию, можно найти здесь: http://codersatwork.wordpress.com/2010/02/13/use-spring-security-for-authorization-only-not-for-authentication/
Я также добавил исходный код и тестовые примеры в http://code.google.com/p/spring-security-with-authorization-only/source/browse/
Ответ 5
Я пытаюсь понять аутентификацию CAS с нашей собственной авторизацией и запутался, так как объект User в Spring Security всегда ожидает, что пароль будет заполнен, и мы не заботимся об этом в нашем сценарии. После прочтения сообщения Surabh кажется, что трюк состоит в том, чтобы вернуть пользовательский объект пользователя без ввода пароля. Я попробую это и посмотрю, работает ли он в моем случае. Надеюсь, ни один другой код в цепочке не будет ожидать пароля в объекте User.
Ответ 6
Я использую авторизацию следующим образом:
-
Внесите связанный с авторизацией bean в мой собственный bean:
@Autowired
private AccessDecisionManager accessDecisionManager;
@Autowired
FilterSecurityInterceptor filterSecurityInterceptor;
-
Используйте этот bean следующим образом:
FilterInvocation fi = new FilterInvocation(rundata.getRequest(), rundata.getResponse(), new FilterChain() {
public void doFilter(ServletRequest arg0, ServletResponse arg1) throws IOException, ServletException {
// TODO Auto-generated method stub
}
});
FilterInvocationDefinitionSource objectDefinitionSource = filterSecurityInterceptor.getObjectDefinitionSource();
ConfigAttributeDefinition attr = objectDefinitionSource.getAttributes(fi);
Authentication authenticated = new Authentication() {
...........
public GrantedAuthority[] getAuthorities() {
GrantedAuthority[] result = new GrantedAuthority[1];
result[0] = new GrantedAuthorityImpl("ROLE_USER");
return result;
}
};
accessDecisionManager.decide(authenticated, fi, attr);
Ответ 7
Я тоже потратил много часов на изучение того, как реализовать пользовательскую авторизацию без аутентификации.
Процесс аутентификации является внешним для нашей системы (на основе единого входа). Я сделал это, как указано ниже, и это работает !!! (Я уверен, что есть много других способов сделать это лучше, но этот способ достаточно хорошо подходит для моего сценария)
Сценарий: пользователь уже аутентифицирован во внешней системе, и вся информация, необходимая для авторизации, присутствует в запросе
1. Необходимо создать конфигурацию безопасности, включив глобальный метод безопасности, как показано ниже.
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
class SpringWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final HttpSecurity http) throws Exception {
}
}
2.) Внедрите Spring PermissionEvaluator, чтобы разрешить, следует ли разрешить или отклонить запрос
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
public boolean authorize(final String groups, final String role) {
boolean allowed = false;
System.out.println("Authorizing: " + groups + "...");
if (groups.contains(role)) {
allowed = true;
System.out.println(" authorized!");
}
return allowed;
};
@Override
public boolean hasPermission(final Authentication authentication, final Object groups, final Object role) {
return authorize((String) groups, (String) role);
};
@Override
public boolean hasPermission(final Authentication authentication, final Serializable targetId, final String targetType, final Object permission) {
return authorize((String) targetId, (String) permission);
};
}
3.) Добавить MethodSecurityConfig
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
return expressionHandler;
}
}
4.) Добавьте @PreAuthorize в свой контроллер, как показано ниже. В этом примере все группы пользователей присутствуют в заголовке запроса с ключом "availableUserGroups". Затем он передается в CustomPermissionEvaluator для проверки авторизации. Обратите внимание, что spring автоматически передает объект аутентификации в метод hasPermission. Так что, если вы хотите загрузить пользователя и проверить с помощью метода пружины hasRole, то это можно использовать.
@PreAuthorize("hasPermission(#userGroups, 'ADMIN')")
@RequestMapping(value = "/getSomething")
public String getSomething(@RequestHeader(name = "availableUserGroups") final String userGroups) {
return "resource allowed to access";
}
Обработка других сценариев: 1.) В сценарии, в котором вы хотите загрузить пользователя, прежде чем сможете выполнить авторизацию. Вы можете использовать пружинные фильтры предварительной аутентификации и делать это аналогичным образом. Пример ссылки: http://www.learningthegoodstuff.com/2014/12/spring-security-pre-authentication-and.html