sf
jiangping
2025-04-30 dcdb0231034810232f2542f3865666ebf72daf11
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package com.doumee.config.shiro;
 
import com.alibaba.fastjson.JSON;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.LoginUserInfo;
import com.doumee.core.utils.Constants;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.MapCache;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.http.HttpStatus;
 
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.Deque;
import java.util.LinkedList;
 
/**
 * Shiro认证过滤器,处理未认证情况的响应
 * @author Eva.Caesar Liu
 * @date 2023/04/17 12:11
 */
public class ShiroAuthFilter extends FormAuthenticationFilter {
 
    public ShiroAuthFilter(SessionManager sessionManager,ShiroCacheManager shiroCacheManager) {
        super();
        this.sessionManager =   (ShiroSessionManager)sessionManager;
        this.cache = shiroCacheManager.getCache("shiro_redis_cache");
    }
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)  {
        return false;
    }
 
    private int maxSession = 1; //最大会话数量
 
    private boolean kickOutAfter = false;   //踢出前者还是后者
    private Cache<String, Deque<Serializable>> cache; //缓存管理
 
 
    private ShiroSessionManager sessionManager;  //会话管理
 
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        Subject subject = getSubject(request, response);
        if (!subject.isAuthenticated() && !subject.isRemembered()) { //如果不是认证过和记住密码的,就直接放行请求,避免造成访问过慢
           // return Boolean.TRUE;
        }
        Session session = subject.getSession(); //获取会话session
        Object principal = subject.getPrincipal();
        Serializable sessionId = session.getId();
        LoginUserInfo userInfo = (LoginUserInfo) principal;
        if(userInfo == null || !Constants.equalsInteger(userInfo.getType(), Constants.UserType.ZHUBO.getKey()) ){
            HttpServletResponse servletResponse = (HttpServletResponse) response;
            servletResponse.setHeader("content-type", "application/json;charset=UTF-8");
            servletResponse.getWriter().write(JSON.toJSONString(ApiResponse.failed(HttpStatus.UNAUTHORIZED.value(), "未登录或登录信息已过期")));
            return Boolean.FALSE;
        }
        String userName = userInfo.getCompanyId() +"_"+ userInfo.getId();
        Deque<Serializable> deque = cache.get(userName);
        if (deque == null) {
            deque = new LinkedList<>();
        }
        if (!deque.contains(sessionId) && session.getAttribute("kickOut") == null) {
            deque.push(sessionId);
            cache.put(userName, deque);
        }
        while (deque.size() > maxSession) {
            Serializable kickOutSessionId;
            if (kickOutAfter) {
                kickOutSessionId = deque.removeFirst();
                cache.put(userName, deque);
            } else {
                kickOutSessionId = deque.removeLast();
                cache.put(userName, deque);
            }
 
            try {
                Session kickOutSession = sessionManager.getSession(new DefaultSessionKey(kickOutSessionId));
                if (kickOutSession != null){
                    kickOutSession.setAttribute("kickOut", Boolean.TRUE);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
 
        if (session!=null && session.getAttribute("kickOut") != null && (Boolean) session.getAttribute("kickOut") == true) {
            try {
                subject.logout();
                if(deque!=null){
                    deque.remove(sessionId);
                    cache.put(userName, deque);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            saveRequest(request);
            HttpServletResponse servletResponse = (HttpServletResponse) response;
            servletResponse.setHeader("content-type", "application/json;charset=UTF-8");
            servletResponse.getWriter().write(JSON.toJSONString(ApiResponse.failed(HttpStatus.UNAUTHORIZED.value(), "未登录或登录信息已过期")));
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }
 
    public int getMaxSession() {
        return maxSession;
    }
 
    public void setMaxSession(int maxSession) {
        this.maxSession = maxSession;
    }
 
    public boolean isKickOutAfter() {
        return kickOutAfter;
    }
 
    public void setKickOutAfter(boolean kickOutAfter) {
        this.kickOutAfter = kickOutAfter;
    }
 
    public Cache<String, Deque<Serializable>> getCache() {
        return cache;
    }
 
    public void setCache(Cache<String, Deque<Serializable>> cache) {
        this.cache = cache;
    }
 
    public ShiroSessionManager getSessionManager() {
        return sessionManager;
    }
 
    public void setSessionManager(ShiroSessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }
}