【发布时间】:2014-11-18 05:43:03
【问题描述】:
有什么方法可以通过springSecurityService 注销其他人?
(例如,如果一个普通用户离开一天并忘记注销,而经理想要注销他们的帐户。)
【问题讨论】:
有什么方法可以通过springSecurityService 注销其他人?
(例如,如果一个普通用户离开一天并忘记注销,而经理想要注销他们的帐户。)
【问题讨论】:
我已经在我的应用程序中完成了,管理员用户可以从当前登录到系统的所有用户列表中强制注销任何用户。
我将所有当前登录到系统的用户发送到 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;
}
【讨论】:
springSecurityService 本身不具备此功能。
但是,没有什么能阻止您创建自己的 ServletFilter 以跟踪会话 ID 和安全主体并公开控制器和页面以使登录的关联会话无效。
【讨论】:
session 对象在每个用户登录时获取他们的会话ID,但是我使用什么类或对象来使任意会话通过ID 无效?
这就是我的做法。
编辑:下面的示例使用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.xml 和 grails-app/conf/WebXmlConfig.groovy 的编辑。 sessionDestroyed 方法在容器超时会话时调用,在我的例子中是 10 分钟。