2

我对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 ?
    }
}
4

5 回答 5

2

以上都是伟大而完美的解决方案。但是我使用了一种解决方案,效果很好。ThreadLocal 使用的多租户 ID

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();

然后使用请求对象获取您的自定义参数

于 2013-03-21T08:11:45.843 回答
1

如果您需要使用额外的表单参数来操作用户名和密码,您可以实现自己的 AuthenticationProcessingFilter

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

此类将具有对 HttpRequest 的完全访问权限,因此可以访问您提交的所有其他参数。如果您的目标是以某种方式使用这些值来修改用户名和密码,那么您可以在这里进行。

于 2009-10-27T08:55:55.150 回答
1

这里的技巧是您需要创建一个新的 AuthenciationToken(可能)扩展 UsernameAndPasswordAuthenicationToken 并且正如@emills 所说,您需要实现一个新的 AuthenciationProcessingFilter 以将请求值映射到令牌并将它们提交给 AuthenicationManager。

基本上有几个部分可以在 spring-security 中实现自定义身份验证链

  • AuthenicationToken- 身份验证请求的详细信息及其结果,即包含您进行身份验证所需的凭据
  • AuthenicationProvider- 向 AuthenicationManager 注册,接受您的 AuthenicationToken 并验证用户并返回具有授予权限集的令牌
  • AuthenciationFilter- 实际上不必是一个过滤器,只需使用 AbstractProcessingFilter 会让你的生活更轻松一些
于 2009-10-27T09:38:18.857 回答
1

我会这样:

<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;
}

现在您有了用户名、密码和详细信息。

于 2009-10-27T18:46:24.380 回答
1

我做过类似的事情,但与任何人在这里建议的不同。我并不是说这是“正确”的做法——但它对我来说效果很好。在 Principal 对象中有用户,并且在 AuthenticationToken 中还有一个 Details 对象,您可以存储其他登录信息的 Map(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 对象,或将其作为参数传递。我在 Spring Security Filter 链末尾的 SecurityFilter 中执行此代码。

<bean id="requestFormFilter" class="...RequestFormDetails">
   <custom-filter position="LAST" />
</bean> 
于 2009-10-27T19:12:44.033 回答