Spring Security会话并发

维迪亚努·阿德里安(Videanu Adrian)

我有一个使用Spring 4.0和Security 3.2构建的应用程序,并且我想实现会话并发性,但是它似乎不起作用。安全性的所有其他方面都工作正常。这是我的xml配置:
首先在我的web.xml中:

<listener>
    <listener-class>
        org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener> 

然后在我的security.xml中

<security:http  auto-config="false" 
                use-expressions="true"
                authentication-manager-ref="authManager"
                access-decision-manager-ref="webAccessDecisionManager"
                entry-point-ref="authenticationEntryPoint">             

    <security:intercept-url pattern="/agent/**" access="hasAnyRole('ROLE_AGENT')" />
    <security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />       
    <security:intercept-url pattern="/public/**" access="permitAll" />
    <security:intercept-url pattern="/**" access="permitAll" />

    <security:session-management session-authentication-strategy-ref="sas"
                                 invalid-session-url="/public/login.xhtml"/>

    <security:logout logout-success-url="/public/login.xhtml" 
                     invalidate-session="true" 
                     delete-cookies="true"/>
    <security:expression-handler ref="webExpressionHandler"/>

    <security:custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />
    <security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
</security:http>

<bean id="authenticationEntryPoint"  class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <constructor-arg index="0" value="/public/login.xhtml" />
</bean>

<bean id="customAuthenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
   p:defaultFailureUrl="/public/login.xhtml" />

<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>

 <bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
    <constructor-arg index="0" ref="sessionRegistry"/>
    <constructor-arg index="1" value="/session-expired.htm"/>       
</bean>

<bean id="myAuthFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    <property name="sessionAuthenticationStrategy" ref="sas" />
    <property name="authenticationManager" ref="authManager" />
    <property name="authenticationFailureHandler" ref="customAuthenticationFailureHandler"/>
</bean>

<bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
    <constructor-arg name="sessionRegistry" ref="sessionRegistry" />
    <property name="maximumSessions" value="1" />
    <property name="exceptionIfMaximumExceeded" value="true" />
</bean>  

<bean id="authManager" class="org.springframework.security.authentication.ProviderManager">
    <property name="providers">
        <list>  
            <ref bean="myCompLdapAuthProvider"/>        
            <ref bean="myCompDBAuthProvider"/>
        </list>     
    </property>     
</bean>

我的UserDetails实现hashCode()和equals(),并且所有这些并发会话限制不起作用。经过一些调试会话后,我观察到在sessionRegistry中从未找到我的会话,我想这是主要原因,但是我不知道为什么!
知道我在这里做错了什么吗?

PS我的调试日志中有这样的记录:

(FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 2 of 11 in     additional filter chain; firing Filter: 'ConcurrentSessionFilter'
(FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 3 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
(FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
(FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 5 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
(FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
(FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
(FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
(AnonymousAuthenticationFilter.java:107) - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@96cf68e: Principal: MyUserDetails [username=adrian.videanu, dn=org.springframework.ldap.core.DirContextAdapter: dn=cn=Adrian Videanu,ou=IT,ou=Organization .....

所以过滤器被调用...

更新

我可以看到会话创建事件已发布,因为我在日志中有此行:

(HttpSessionEventPublisher.java:66) - Publishing event: org.springframework.security.web.session.HttpSessionCreatedEvent[source=org.apache.catalina.session.StandardSessionFacade@3827a0aa]  

但我从没想过应该从SessionRegistryImpl中点击registerNewSession方法。另外,当我最初打开登录页面时,还会调用HttpSessionEventPublisher,因为我猜是在创建会话时,但是在输入凭据并推送提交后,不再调用HttpSessionEventPublisher。

更新2
作为测试,我将SessionRegistryImpl注入到我的一个bean中,以尝试访问其某些方法:

@Named
@Scope("view")
public class UserDashboardMB  implements Serializable {

private static final long serialVersionUID = 1L;

@Inject
private SessionRegistry sessionRegistry;

public void init(){

    System.out.println("-- START INIT -- ");
    List<Object> principals = sessionRegistry.getAllPrincipals();

    System.out.println("Principals = "+principals);

    for (Object p:principals){
        System.out.println("Principal = "+p);
    }

    System.out.println("-- STOP INIT -- ");
}   
}  

输出为:
INFO:-START INIT-
INFO:Principals = []
INFO:-STOP INIT-
因此,那里没有任何内容。

更新3
我已经用Serge提供的那个替换了“ sas” bean,但是它似乎仍然不起作用。我再次启用了调试器,问题是在类UsernamePasswordAuthenticationFilter的方法doFilter()上没有我的请求得到应有的处理。这是doFilter()的一部分:

 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    if (!requiresAuthentication(request, response)) {
        chain.doFilter(request, response);

        return;
    }

    if (logger.isDebugEnabled()) {
        logger.debug("Request is to process authentication");
    }

    Authentication authResult;
// rest of method here
}

从我在调试器中看到的内容来看,我的请求似乎不需要auth和chain.doFilter(request,response); 被调用。

更新4
我想我找到了问题。筛选器未按预期运行,因为filterUrl参数不合适。正如我在文档中看到的:

默认情况下,此过滤器响应URL / j_spring_security_check。

但是我的登录部分是通过JSF托管的bean和操作实现的。现在,我的登录表单位于/public/login.xhtml,并且发布登录信息的URL相同。如果我将其设置为filterUrl,则会遇到问题,因为在初始形式渲染时也会被调用,并且由于没有设置用户名/密码,因此存在无限循环。
知道如何克服吗?
这是我的LoginManagedBean的样子:

@Named
@Scope("request")
public class LoginMB implements Serializable {

private static final long serialVersionUID = 1L;

@Autowired
@Qualifier("authManager")
private AuthenticationManager authenticationManager;

// setters and getters

public String login(){

    FacesContext context = FacesContext.getCurrentInstance();

    try {
        Authentication request = new UsernamePasswordAuthenticationToken(this.getUsername(), this.getPassword());
        Authentication result = authenticationManager.authenticate(request);
        SecurityContextHolder.getContext().setAuthentication(result);

        // perform some extra logic here and return protected page
        return "/agent/dashboard.xhtml?faces-redirect=true";

    } catch (AuthenticationException e) {
        e.printStackTrace();                        
        logger.error("Auth Exception ->"+e.getMessage());
        FacesMessage fm = new FacesMessage("Invalid user/password");
        fm.setSeverity(FacesMessage.SEVERITY_ERROR);
        context.addMessage(null, fm);                   
    }
    return null;
   }
}
维迪亚努·阿德里安(Videanu Adrian)

我终于设法解决了这个问题。问题是由于我在标准弹簧过滤器和自定义jsf登录表单之间进行了混合设置。正如Serge所指出的,我在xml conf中只留下了“ sas” bean,在我的LoginMB中,我已经手动并以编程方式调用了SessionAuthenticationStrategy onAuthentication()方法。所以现在我的LoginMB看起来像:

@Named
@Scope("request")
public class LoginMB implements Serializable {

@Autowired
@Qualifier("authManager")
private AuthenticationManager authenticationManager;

@Inject
@Qualifier("sas")
private SessionAuthenticationStrategy sessionAuthenticationStrategy;


public String login(){

    FacesContext context = FacesContext.getCurrentInstance();

    try {
        Authentication authRequest = new UsernamePasswordAuthenticationToken(this.getUsername(), this.getPassword());
        Authentication result = authenticationManager.authenticate(authRequest);
        SecurityContextHolder.getContext().setAuthentication(result);

        HttpServletRequest httpReq = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
        HttpServletResponse httpResp = (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();

        sessionAuthenticationStrategy.onAuthentication(result, httpReq, httpResp);

        // custom logic here 

        return "/agent/dashboard.xhtml?faces-redirect=true";

    }catch(SessionAuthenticationException sae){
        sae.printStackTrace();
        logger.error("Auth Exception ->"+sae.getMessage());

        String userMessage = "Session auth exception!";
        if (sae.getMessage().compareTo("Maximum sessions of 1 for this principal exceeded") == 0){
            userMessage = "Cannot login from more than 1 location.";
        }

        FacesMessage fm = new FacesMessage(userMessage);
        fm.setSeverity(FacesMessage.SEVERITY_FATAL);
        context.addMessage(null, fm);
    }       
    catch (AuthenticationException e) {
        e.printStackTrace();                        
        logger.error("Auth Exception ->"+e.getMessage());
        FacesMessage fm = new FacesMessage("Invalid user/password");
        fm.setSeverity(FacesMessage.SEVERITY_FATAL);
        context.addMessage(null, fm);                   
    }
    return null;
}

现在,会话已注册,并且会话限制正在起作用。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Grails Spring Security最大并发会话

来自分类Dev

每个用户组或单个用户的Spring Security并发会话控制

来自分类Dev

Spring Security 3.1:会话并发控制不起作用,为什么?

来自分类Dev

Spring Security:无法注销/使会话无效

来自分类Dev

Spring Security + Ajax会话超时问题

来自分类Dev

不使用Cookie的Spring Security会话

来自分类Dev

Spring Security的分布式会话

来自分类Dev

Spring Security + Ajax会话超时问题

来自分类Dev

Spring Security注销会话未失效

来自分类Dev

如何在Spring Security中启用会话并设置会话超时

来自分类Dev

Spring Boot-如何终止当前的Spring Security会话?

来自分类Dev

如何使用 Spring Security 在 Spring Boot 中管理会话?

来自分类Dev

Spring MVC +会话会话(多个选项卡)+带有CSRF + Thymeleaf的Spring Security

来自分类Dev

如何使用Spring Security获取会话超时消息

来自分类Dev

Spring Security删除用户-会话仍处于活动状态

来自分类Dev

SpEL-Spring Security中的访问会话对象

来自分类Dev

实例化Spring Security会话时引发错误

来自分类Dev

如何在Spring Security中关闭HTTP会话超时?

来自分类Dev

Spring Security中特定于注销的会话ID

来自分类Dev

将用户信息存储到会话中,Spring Security

来自分类Dev

Spring Security + LDAP:登录后立即清除会话

来自分类Dev

Spring Security自定义会话超时陷入无限循环

来自分类Dev

如何在Spring Security中关闭HTTP会话超时?

来自分类Dev

带有 LDAP 注销的 Spring Security 无法删除会话

来自分类Dev

使用Spring Boot在Spring Security中无法阻止同一用户的多个并发登录

来自分类Dev

使用Spring Security配置应用程序以接受HTTP请求并发送HTTPS响应

来自分类Dev

使用Spring Security配置应用程序以接受HTTP请求并发送HTTPS响应

来自分类Dev

CSRF与Spring Security集成时,会话超时导致Spring MVC中的访问被拒绝

来自分类Dev

带有Spring Security的Spring Session创建两个会话

Related 相关文章

  1. 1

    Grails Spring Security最大并发会话

  2. 2

    每个用户组或单个用户的Spring Security并发会话控制

  3. 3

    Spring Security 3.1:会话并发控制不起作用,为什么?

  4. 4

    Spring Security:无法注销/使会话无效

  5. 5

    Spring Security + Ajax会话超时问题

  6. 6

    不使用Cookie的Spring Security会话

  7. 7

    Spring Security的分布式会话

  8. 8

    Spring Security + Ajax会话超时问题

  9. 9

    Spring Security注销会话未失效

  10. 10

    如何在Spring Security中启用会话并设置会话超时

  11. 11

    Spring Boot-如何终止当前的Spring Security会话?

  12. 12

    如何使用 Spring Security 在 Spring Boot 中管理会话?

  13. 13

    Spring MVC +会话会话(多个选项卡)+带有CSRF + Thymeleaf的Spring Security

  14. 14

    如何使用Spring Security获取会话超时消息

  15. 15

    Spring Security删除用户-会话仍处于活动状态

  16. 16

    SpEL-Spring Security中的访问会话对象

  17. 17

    实例化Spring Security会话时引发错误

  18. 18

    如何在Spring Security中关闭HTTP会话超时?

  19. 19

    Spring Security中特定于注销的会话ID

  20. 20

    将用户信息存储到会话中,Spring Security

  21. 21

    Spring Security + LDAP:登录后立即清除会话

  22. 22

    Spring Security自定义会话超时陷入无限循环

  23. 23

    如何在Spring Security中关闭HTTP会话超时?

  24. 24

    带有 LDAP 注销的 Spring Security 无法删除会话

  25. 25

    使用Spring Boot在Spring Security中无法阻止同一用户的多个并发登录

  26. 26

    使用Spring Security配置应用程序以接受HTTP请求并发送HTTPS响应

  27. 27

    使用Spring Security配置应用程序以接受HTTP请求并发送HTTPS响应

  28. 28

    CSRF与Spring Security集成时,会话超时导致Spring MVC中的访问被拒绝

  29. 29

    带有Spring Security的Spring Session创建两个会话

热门标签

归档