是否可以在 Spring 中以基于表单的身份验证发送更多数据?

发布于 2024-08-08 20:31:25 字数 1366 浏览 6 评论 0原文

我对 Spring 框架 和 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 ?
    }
}

I am relatively new to the Spring Framework and Spring security.

I have used a custom authentication scheme, 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>

and the corresponding code:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

美男兮 2024-08-15 20:31:25

以上都是很棒且完美的解决方案。
但我使用了一种解决方案,效果非常好。
用于 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 {

    }
}

spring security xml 的多租户 ID

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

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

All above are great and perfect solutions.
But I have used a workaround kind of solution which works perfectly fine.
Used multitenant id for 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 {

    }
}

spring security xml

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

Access request object in your Authentication Class

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

Then use the request object to get your custom parameters

坏尐絯℡ 2024-08-15 20:31:25

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

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

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

If you need to use additional form parameters in order to manipulate the username and password, you can implement your own AuthenticationProcessingFilter

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

This class will have full access to the HttpRequest and therefore all the additional parameters you submit. If your goal is to somehow use these values to modify the username and password, this is where you would do it.

一人独醉 2024-08-15 20:31:25

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

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

  • - 身份验证请求及其结果的详细信息,即包含验证
  • AuthenicationProvider 所需的凭据- 向 AuthenicationManager 注册,接受您的 AuthenicationToken 并验证用户,并返回一个具有授予权限集的令牌
  • AuthenciationFilter - 实际上不必是一个过滤器,只需使用 AbstractProcessingFilter 将使您的生活变得更轻松

The trick here is that you need to create a new AuthenicationToken (maybe) extending UsernameAndPasswordAuthenicationToken and as @emills says you need to then implement a new AuthenciationProcessingFilter to map the request values to the token and submit these to the AuthenicationManager.

Basically there are a couple of parts to implementing a custom authenication chain in spring-security

  • AuthenicationToken - details of the authenication request and it's result, ie contains credentials you require to authenticate
  • AuthenicationProvider - registered with the AuthenicationManager, accepts your AuthenicationToken and validates the user and returns a token with the granted authorities set
  • AuthenciationFilter - doesn't actually have to be a filter just using AbstractProcessingFilter will make your life a little easier
全部不再 2024-08-15 20:31:25

我会这样:

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

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

I would go this way:

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

This is the class that holds the properties:

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

Now you have the username, password and the details.

堇年纸鸢 2024-08-15 20:31:25

我做过类似的事情,但与任何人在这里建议的不同。我并不是说这是“正确”的方法 - 但它对我来说非常有效。在主体对象中有用户,在 AuthenticationToken 中还有一个详细信息对象,您可以存储其他登录信息的 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> 

I've done a similar thing, but different then anyone has suggested here. I am not saying this is the "right" way to do it - but it's worked very well for me. In the Principal object there is the user and there is also a Details object in the AuthenticationToken that you can store a Map(String, String) of other login info.

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

Now anywhere in your code you get use the SecurityContext to propagate this security related info without having to couple it to your UserDetails object, or pass it as arguments. I do this code in a SecurityFilter at the end of the Spring Security Filter chain.

<bean id="requestFormFilter" class="...RequestFormDetails">
   <custom-filter position="LAST" />
</bean> 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文