賬號在同一時間只能在一處登錄(非單點登錄)實現(xiàn)方式大致三種:
- session隔離
- 數(shù)據(jù)庫記錄
- shiro實現(xiàn)
shiro實現(xiàn)方式
1.shiro配置
<bean id="myRealm" class="com.sys.shiro.MyRealm" />
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.MemorySessionDAO"></bean>
<bean id="sessionManager"
class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="globalSessionTimeout" value="1800000" />
<property name="deleteInvalidSessions" value="true" />
<property name="sessionValidationSchedulerEnabled" value="true" />
<property name="sessionValidationInterval" value="1800000" />
<property name="sessionIdCookie" ref="sessionIdCookie" />
<property name="sessionDAO" ref="sessionDAO"/>
</bean>
<!-- Shiro默認會使用Servlet容器的Session,可通過sessionMode屬性來指定使用Shiro原生Session -->
<!-- 即<property name="sessionMode" value="native"/>,詳細說明見官方文檔 -->
<!-- 這里主要是設(shè)置自定義的單Realm應(yīng)用,若有多個Realm,可使用'realms'屬性代替 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="shiroCacheManager" />
<property name="realm" ref="myRealm" />
<property name="sessionManager" ref="sessionManager" />
</bean>
2.代碼
@Autowired
private SessionDAO sessionDAO;
/**
* 實現(xiàn)用戶登錄
* @param username
* @param password
* @return
*/
@RequestMapping(value = "doLogin")
public ModelAndView Login(String username, String password) {
ModelAndView mav = new ModelAndView();
User user = loginService.getUser(username);
if (user == null) {
mav.setViewName("login");
mav.addObject("msg", "用戶不存在");
return mav;
}
if (!user.getPassword().equals(password)) {
mav.setViewName("login");
mav.addObject("msg", "賬號密碼錯誤");
return mav;
}
Collection<Session> sessions = sessionDao.getActiveSessions();
for (Session session : sessions) {
System.out.println("登錄用戶" + session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
//shiro session可以拿到已經(jīng)登陸的username
System.out.println("登錄用戶" + session.getAttribute("userName"));
if (username.equals(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY))) {
mav.setViewName("login");
mav.addObject("msg", "該用戶已登錄");
// session.setTimeout(0); //這里就把session清除
sessionDAO.delete(session); //session清除西土,
return mav;
}
}
// 登錄后存放進shiro token
UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassword());
Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);
//httpSession
currentUser.getSession().setAttribute("loginName",username);
//shiro Session
currentUser.getSession(true).setAttribute("userName",username);
// 登錄成功后會跳轉(zhuǎn)到successUrl配置的鏈接,不用管下面返回的鏈接祖很。
mav.setViewName("redirect:home");
return mav;
}
3.結(jié)束!
- shiro獲取所有在線用戶方法
//apache shiro獲取所有在線用戶:
Collection sessions = sessionDAO.getActiveSessions();
for(Session session:sessions){
System.out.println("登錄ip:"+session.getHost());
System.out.println("登錄用戶"+session.getAttribute(DefaultWebContext.PRINCIPALS_SESSION_KEY));
System.out.println("最后操作日期:"+session.getLastAccessTime());
}
- session移除另外一種方式
/*
*在 LocalAuthorizingRealm 中,用戶登錄進行認證之前候醒,先將該用戶的其他session移除
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String userName = (String)authenticationToken.getPrincipal();
//處理session
DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
DefaultWebSessionManager sessionManager = (DefaultWebSessionManager)securityManager.getSessionManager();
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();//獲取當前已登錄的用戶session列表
for(Session session:sessions){
//清除該用戶以前登錄時保存的session
if(userName.equals(String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)))) {
sessionManager.getSessionDAO().delete(session);
}
}
String pwd = null;
return new SimpleAuthenticationInfo(userName,pwd,getName());
}