Можно ли отправить больше данных в форме проверки подлинности в Spring? - PullRequest
2 голосов
/ 27 октября 2009

Я относительно новичок в Spring Framework и безопасности Spring.

Я использовал собственную схему аутентификации, HTML:

<form action="j_spring_security_check">
    <input type="text" name="j_username" value="abc"/>
    <input type="text" name="j_password" value="abc"/>
    <input type="text" name="myCustom1" value="pqr"/> <!-- maybe type="hidden" -->
    <input type="text" name="myCustom2" value="pqr"/> <!-- maybe type="hidden" -->
</form>

и соответствующий код:

public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider
{
    @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken)
    throws AuthenticationException
    {
        System.out.println("Method invoked : additionalAuthenticationChecks isAuthenticated ? :"+usernamePasswordAuthenticationToken.isAuthenticated());
    }

    @Override protected UserDetails retrieveUser(String username,UsernamePasswordAuthenticationToken authentication)
    throws AuthenticationException
    {
        System.out.println("Method invoked : retrieveUser");
        //I have Username,password:
        //HOW CAN I ACCESS "myCustom1", "myCustom2" here ?
    }
}

Ответы [ 5 ]

2 голосов
/ 21 марта 2013

Все вышеперечисленное - отличные и совершенные решения. Но я использовал обходное решение, которое прекрасно работает. Используемый мультитенантный идентификатор для ThreadLocal

package com.mypackage.servlet;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.util.Assert;

public class ThreadLocalContextUtil implements Filter{
     private static final ThreadLocal<Object> contextHolder =
                new ThreadLocal<Object>();

       public static void setTenantId(Object tenantId) {
          Assert.notNull(tenantId, "customerType cannot be null");
          contextHolder.set(tenantId);
       }

       public static Object getTenantId() {
          return contextHolder.get();
       }

       public static void clearTenant() {
          contextHolder.remove();
       }

    public void destroy() {

    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        // Set the tenant Id into a ThreadLocal object
        ThreadLocalContextUtil.setTenantId(request);
        if(chain != null)
            chain.doFilter(request, response);
        else {
            //error
        }
    }

    public void init(FilterConfig filterconfig) throws ServletException {

    }
}

пружина безопасности xml

<security:http auto-config="true" use-expressions="true" access-denied-page="/forms/auth/403" >
    <security:custom-filter before="FIRST" ref="tenantFilter" />
    ......
    </security:http>

Объект запроса доступа в вашем классе аутентификации

HttpServletRequest currRequest = (HttpServletRequest) ThreadLocalContextUtil.getTenantId();

Затем используйте объект запроса для получения пользовательских параметров

1 голос
/ 27 октября 2009

Я сделал похожую вещь, но отличается от того, что здесь предлагали. Я не говорю, что это «правильный» способ сделать это - но он работал очень хорошо для меня. В объекте Principal есть пользователь, а также объект Details в AuthenticationToken, в котором можно хранить карту (String, String) другой информации для входа в систему.

public class RequestFormDeatils extends SpringSecurityFilter {

   protected void doFilterHttp(HttpServletRequest request, ...) {
      SecurityContext sec = SecurityContextHolder.getContent();
      AbstractAuthenticationToken auth = (AbstractAuthenticationToken)sec.getAuthentication();
      Map<String, String> m = new HashMap<String, String>;
      m.put("myCustom1", request.getParamtere("myCustom1"));
      m.put("myCustom2", request.getParameter("myCustom2"));
      auth.setDetails(m);
}

Теперь в любом месте вашего кода вы используете SecurityContext для распространения этой информации, связанной с безопасностью, без необходимости связывать ее с вашим объектом UserDetails или передавать в качестве аргументов. Я делаю этот код в SecurityFilter в конце цепочки Spring Security Filter.

<bean id="requestFormFilter" class="...RequestFormDetails">
   <custom-filter position="LAST" />
</bean> 
1 голос
/ 27 октября 2009

Хитрость в том, что вам нужно создать новый AuthenicationToken (возможно), расширяющий UsernameAndPasswordAuthenicationToken, и, поскольку @emills говорит, что вам нужно затем реализовать новый AuthenciationProcessingFilter для сопоставления значений запроса токену и отправки их в AuthenicationManager.

По сути, есть пара частей для реализации пользовательской цепочки аутентификации в Spring-Security

  • AuthenicationToken - информация о запросе на аутентификацию и его результате, т.е. содержит учетные данные, необходимые для аутентификации
  • AuthenicationProvider - зарегистрирован в AuthenicationManager, принимает ваш AuthenicationToken и проверяет пользователя и возвращает токен с установленными полномочиями
  • AuthenciationFilter - на самом деле не обязательно быть фильтром, просто использование AbstractProcessingFilter сделает вашу жизнь немного проще
1 голос
/ 27 октября 2009

Я бы пошел по этому пути:

<bean id="authenticationProcessingFilter"  
    class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  ...
  <property name="authenticationDetailsSource">
    <bean class="org.acegisecurity.ui.AuthenticationDetailsSourceImpl">
        <property name="clazz"  
           value="com.MyAuthenticationDetails"/>
    </bean>
  </property>
</bean>  

Это класс, который содержит свойства:

package com;
import javax.servlet.http.HttpServletRequest;
import org.acegisecurity.ui.WebAuthenticationDetails;
public class MyAuthenticationDetails extends WebAuthenticationDetails {
    public MyAuthenticationDetails() {
      super();
    }
    //This constructor will be invoqued by the filter
    public MyAuthenticationDetails(HttpServletRequest request) {
        super(request);
        this.myCustom1 = request.getParameter("myCustom1");
    }
    public String getMyCustom1() {
        return myCustom1;
    }
    private String myCustom1;
}

Теперь у вас есть имя пользователя, пароль и данные.

1 голос
/ 27 октября 2009

Если вам нужно использовать дополнительные параметры формы для манипулирования именем пользователя и паролем, вы можете реализовать свой собственный AuthenticationProcessingFilter

http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/ui/webapp/AuthenticationProcessingFilter.html

Этот класс будет иметь полный доступ к HttpRequest и, следовательно, ко всем дополнительным параметрам, которые вы отправляете. Если ваша цель состоит в том, чтобы как-то использовать эти значения для изменения имени пользователя и пароля, это то место, где вы должны это сделать.

...