SpringSecurityService:注销其他用户?

Posted

技术标签:

【中文标题】SpringSecurityService:注销其他用户?【英文标题】:SpringSecurityService: Log other user out? 【发布时间】:2014-11-18 05:43:03 【问题描述】:

有什么方法可以通过springSecurityService 注销其他人?

(例如,如果一个普通用户离开一天并忘记注销,而经理想要注销他们的帐户。)

【问题讨论】:

【参考方案1】:

我已经在我的应用程序中完成了,管理员用户可以从当前登录到系统的所有用户列表中强制注销任何用户。

    我将所有当前登录到系统的用户发送到 jsp,其中所有登录用户的列表都会显示给管理员用户。

    @PreAuthorize("hasRole('Currently_Logged-In_Users')")
    	@RequestMapping(value = "/getLoggedInUsers", method = RequestMethod.POST)
    	@ResponseBody
    	public Map<String, List<?>> getLoggedInUsers(Map<String, Object> map ,Model model) 
    		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    	      String userName = auth.getName(); 
    	     
    	List<Object> principals = sessionRegistry.getAllPrincipals();
    
    	List<UserInfo> usersInfoList = new ArrayList<UserInfo>();
    
    	for (Object principal: principals) 
    	    if (principal instanceof UserInfo) 
    	    	if(!((UserInfo) principal).getUsername().equals(userName))
    	    	for(SessionInformation sess :sessionRegistry.getAllSessions(principal, false))
        			if(!sess.isExpired())
        				usersInfoList.add((UserInfo) sess.getPrincipal());
        			
    	    	
    	    	
    	    	
    	    
    	
    	
    	Map<String, List<?>> loggedInUserMap = new HashMap<String, List<?>>();
    
    	loggedInUserMap.put("loggenInUsers",
    			usersInfoList);
    
    
    	return loggedInUserMap;
    	
    	

    现在管理员用户可以通过单击用户复选框来选择任何用户或多个用户。并调用强制注销操作。

    @PreAuthorize("hasRole('Currently_Logged-In_Users')")
    	@RequestMapping(value = "/logoutSelectedUsers", method = RequestMethod.POST)
    	@ResponseBody
    	public Map<String, String> forcedLoggedOut(@RequestParam("userList[]")ArrayList<String> userList ,Model model ,HttpServletRequest request ) 
    		
    		Map<String,String> map= new HashMap<String,String>();
    		try
    			
    		String successMessage =null;
    		List<String> userCodeList = new ArrayList<String>();
    		
    		for(String userCode :userList )
    			userCodeList.add(userCode);
    		
    			
    		List<Object> principals = sessionRegistry.getAllPrincipals();
    		for (Object principal: principals) 
    		    if (principal instanceof UserInfo) 
    		    	if(userCodeList.contains(((UserInfo) principal).getUsername()))
    		    		for(SessionInformation sess :sessionRegistry.getAllSessions(principal, false))
    		    			sess.expireNow();
    		    			successMessage = "msg.loggedOutSuccessfully";
    		    			
    		    		
    		    	
    		    
    		
    		
    	
    		map.put("successmsg", successMessage);
    		
    		catch(Exception e)
    			map.put("failmsg", "msg.notLoggedOut");
    			logger.error(e.toString(),e);	
    			
    		return map;
    		
    	

【讨论】:

很好,这正是我正在寻找的东西。我得试试看。 它的工作..因为我做了同样的事情......你可以试试..如果你需要进一步的帮助..你可以问..:)【参考方案2】:

springSecurityService 本身不具备此功能。

但是,没有什么能阻止您创建自己的 ServletFilter 以跟踪会话 ID 和安全主体并公开控制器和页面以使登录的关联会话无效。

【讨论】:

嗯。所以我知道我可以使用内置的session 对象在每个用户登录时获取他们的会话ID,但是我使用什么类或对象来使任意会话通过ID 无效? 这个之前的 SO 问题和答案将帮助您理解我的意思,方法是创建您赢得的 ServletFilter 或 SessionListener 来跟踪会话,然后以它们为目标使它们无效。 ***.com/questions/1499581/…【参考方案3】:

这就是我的做法。

编辑:下面的示例使用webxml plugin。您也可以直接编辑 web.xml。设置超时见this answer。

// src/groovy/com/example/ExpiringSessionEventListener.groovy:
package com.example

import grails.util.Holders
import javax.servlet.http.HttpSessionListener
import javax.servlet.http.HttpSessionEvent
import org.springframework.security.core.context.SecurityContext

public class ExpiringSessionEventListener implements  HttpSessionListener 

    @Override
    public void sessionCreated(HttpSessionEvent event) 
        // Do some logging
    

    @Override
    public void sessionDestroyed(HttpSessionEvent event) 
        SecurityContext securityContext = event.session.getAttribute("SPRING_SECURITY_CONTEXT")
        if (securityContext) 
            UserService userService = Holders.applicationContext.getBean("userService")
            String userName = securityContext.authentication.principal.username
            userService.userLoggedOut(userName, event.session.id, Boolean.TRUE)
        
    



//  grails-app/services/com/example/UserService.groovy:
package com.example

import grails.plugin.springsecurity.annotation.Secured

class UserService 

    @Secured(["ROLE_USER"])
    def userLoggedOut(String userName, String sessionId, Boolean expired) 
        User user = User.findByUsername(userName)
        if (expired) 
            // Do user cleanup stuff after expired session
         else 
            // Do user cleanup stuff after clicking the logout button
        
    

编辑:

// grails-app/conf/WebXmlConfig.groovy:
webxml 
    sessionConfig.sessionTimeout = 10 // minutes
    listener.add = true
    listener.classNames = [
        "com.example.ExpiringSessionEventListener"
    ]

【讨论】:

sessionDestroyed 什么时候被调用?我可以调用它来注销任意用户吗? 我遗漏了拼图的关键部分。请参阅我对 web.xmlgrails-app/conf/WebXmlConfig.groovy 的编辑。 sessionDestroyed 方法在容器超时会话时调用,在我的例子中是 10 分钟。 我错过了你的第二个问题。任意用户是什么意思? 整洁!好吧,我的目标是让一个经理去例如单击按钮以注销任何其他用户。所以,与我们在这里看到的不太一样。不过,这不是一个坏主意。 使用上述方法可以避免管理员注销活动用户的情况。但是,您可以使用服务和侦听器方法中的位,并将它们与 GUI 相关联,在该 GUI 中管理器选择用户并单击注销按钮。您可能想查看spring-security-ui plugin,尽管我认为它不提供任意注销功能。

以上是关于SpringSecurityService:注销其他用户?的主要内容,如果未能解决你的问题,请参考以下文章

springSecurityService.principal 在 tomcat 8.5 中部署为 WAR 时返回 Null

如何使用 grails 在单元测试中模拟 springSecurityService

使用 Grails 3.0.3 将 springSecurityService 注入控制器

我的 Grails 3.3.8 应用程序中 SpringSecurityService 中的 MissingPropertyException

Grails springSecurityService如何设置当前用户

如果登录尝试中我的应用程序的浏览器中没有以前的 JSESSIONID cookie,则 springSecurityService.reauthenticate 不起作用