ZenWebSessionManager.kt 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. package com.gxzc.zen.umps.config
  2. import org.apache.shiro.session.ExpiredSessionException
  3. import org.apache.shiro.session.InvalidSessionException
  4. import org.apache.shiro.session.Session
  5. import org.apache.shiro.session.UnknownSessionException
  6. import org.apache.shiro.session.mgt.DefaultSessionManager
  7. import org.apache.shiro.session.mgt.DelegatingSession
  8. import org.apache.shiro.session.mgt.SessionContext
  9. import org.apache.shiro.session.mgt.SessionKey
  10. import org.apache.shiro.web.servlet.Cookie
  11. import org.apache.shiro.web.servlet.ShiroHttpServletRequest
  12. import org.apache.shiro.web.servlet.ShiroHttpSession
  13. import org.apache.shiro.web.servlet.SimpleCookie
  14. import org.apache.shiro.web.session.mgt.WebSessionKey
  15. import org.apache.shiro.web.util.WebUtils
  16. import org.slf4j.LoggerFactory
  17. import java.io.Serializable
  18. import javax.servlet.ServletRequest
  19. import javax.servlet.ServletResponse
  20. import javax.servlet.http.HttpServletRequest
  21. import javax.servlet.http.HttpServletResponse
  22. /**
  23. * Copied form @link DefaultWebSessionManager
  24. * 解决一次登陆多次直接读取缓存的问题
  25. * 在读取前先读取本地缓存(目前存放于spring-session 中 attribute)
  26. * @author NorthLan
  27. * @date 2018/4/25
  28. * @url https://noahlan.com
  29. */
  30. @Suppress("unused")
  31. class ZenWebSessionManager : DefaultSessionManager {
  32. companion object {
  33. private val log = LoggerFactory.getLogger(ZenWebSessionManager::class.java)
  34. }
  35. var sessionIdCookie: Cookie? = null
  36. var sessionIdCookieEnabled: Boolean = false
  37. var sessionIdUrlRewritingEnabled: Boolean = false
  38. constructor() {
  39. val cookie = SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME)
  40. cookie.isHttpOnly = true //more secure, protects against XSS attacks
  41. this.sessionIdCookie = cookie
  42. this.sessionIdCookieEnabled = true
  43. this.sessionIdUrlRewritingEnabled = true
  44. }
  45. private fun storeSessionId(currentId: Serializable?, request: HttpServletRequest, response: HttpServletResponse) {
  46. if (currentId == null) {
  47. val msg = "sessionId cannot be null when persisting for subsequent requests."
  48. throw IllegalArgumentException(msg)
  49. }
  50. val template = sessionIdCookie
  51. val cookie = SimpleCookie(template)
  52. val idString = currentId.toString()
  53. cookie.value = idString
  54. cookie.saveTo(request, response)
  55. log.trace("Set session ID cookie for session with id {}", idString)
  56. }
  57. private fun removeSessionIdCookie(request: HttpServletRequest, response: HttpServletResponse) {
  58. sessionIdCookie?.removeFrom(request, response)
  59. }
  60. private fun getSessionIdCookieValue(request: ServletRequest, response: ServletResponse): String? {
  61. if (!sessionIdCookieEnabled) {
  62. log.debug("Session ID cookie is disabled - session id will not be acquired from a request cookie.")
  63. return null
  64. }
  65. if (request !is HttpServletRequest) {
  66. log.debug("Current request is not an HttpServletRequest - cannot get session ID cookie. Returning null.")
  67. return null
  68. }
  69. return sessionIdCookie?.readValue(request, WebUtils.toHttp(response))
  70. }
  71. private fun getReferencedSessionId(request: ServletRequest, response: ServletResponse): Serializable? {
  72. var id = getSessionIdCookieValue(request, response)
  73. if (id != null) {
  74. request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
  75. ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE)
  76. } else {
  77. //not in a cookie, or cookie is disabled - try the request URI as a fallback (i.e. due to URL rewriting):
  78. //try the URI path segment parameters first:
  79. id = getUriPathSegmentParamValue(request, ShiroHttpSession.DEFAULT_SESSION_ID_NAME)
  80. if (id == null) {
  81. //not a URI path segment parameter, try the query parameters:
  82. val name = getSessionIdName()
  83. id = request.getParameter(name)
  84. if (id == null) {
  85. //try lowercase:
  86. id = request.getParameter(name.toLowerCase())
  87. }
  88. }
  89. if (id != null) {
  90. request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
  91. ShiroHttpServletRequest.URL_SESSION_ID_SOURCE)
  92. }
  93. }
  94. if (id != null) {
  95. request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id)
  96. //automatically mark it valid here. If it is invalid, the
  97. //onUnknownSession method below will be invoked and we'll remove the attribute at that time.
  98. request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, java.lang.Boolean.TRUE)
  99. }
  100. // always set rewrite flag - SHIRO-361
  101. request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, sessionIdUrlRewritingEnabled)
  102. return id
  103. }
  104. //SHIRO-351
  105. //also see http://cdivilly.wordpress.com/2011/04/22/java-servlets-uri-parameters/
  106. //since 1.2.2
  107. private fun getUriPathSegmentParamValue(servletRequest: ServletRequest, paramName: String): String? {
  108. if (servletRequest !is HttpServletRequest) {
  109. return null
  110. }
  111. var uri: String? = servletRequest.requestURI ?: return null
  112. val queryStartIndex = uri!!.indexOf('?')
  113. if (queryStartIndex >= 0) { //get rid of the query string
  114. uri = uri.substring(0, queryStartIndex)
  115. }
  116. var index = uri.indexOf(';') //now check for path segment parameters:
  117. if (index < 0) {
  118. //no path segment params - return:
  119. return null
  120. }
  121. //there are path segment params, let's get the last one that may exist:
  122. val token = "$paramName="
  123. uri = uri.substring(index + 1) //uri now contains only the path segment params
  124. //we only care about the last JSESSIONID param:
  125. index = uri.lastIndexOf(token)
  126. if (index < 0) {
  127. //no segment param:
  128. return null
  129. }
  130. uri = uri.substring(index + token.length)
  131. index = uri.indexOf(';') //strip off any remaining segment params:
  132. if (index >= 0) {
  133. uri = uri.substring(0, index)
  134. }
  135. return uri //what remains is the value
  136. }
  137. override fun retrieveSession(sessionKey: SessionKey): Session? {
  138. val sessionId = getSessionId(sessionKey)
  139. if (sessionId == null) {
  140. log.debug("Unable to resolve session ID from SessionKey [{}]. Returning null to indicate a " + "session could not be found.", sessionKey)
  141. return null
  142. }
  143. ////////////////////////Add by noahlan//////////////////////////////////
  144. var request: ServletRequest? = null
  145. if (sessionKey is WebSessionKey) {
  146. request = sessionKey.servletRequest
  147. }
  148. if (request != null) {
  149. val s = request.getAttribute(sessionId.toString())
  150. if (s != null) {
  151. return s as Session
  152. }
  153. }
  154. ////////////////////////////////////////////////////////////////////////
  155. val s = retrieveSessionFromDataSource(sessionId)
  156. if (s == null) {
  157. //session ID was provided, meaning one is expected to be found, but we couldn't find one:
  158. val msg = "Could not find session with ID [$sessionId]"
  159. throw UnknownSessionException(msg)
  160. }
  161. ////////////////////////Add by noahlan//////////////////////////////////
  162. if (request != null) {
  163. request.setAttribute(sessionId.toString(), s)
  164. }
  165. ///////////////////////////////////////////////////////////////////////
  166. return s
  167. }
  168. //since 1.2.1
  169. private fun getSessionIdName(): String {
  170. var name: String? = this.sessionIdCookie?.name
  171. if (name == null) {
  172. name = ShiroHttpSession.DEFAULT_SESSION_ID_NAME
  173. }
  174. return name
  175. }
  176. override fun createExposedSession(session: Session, context: SessionContext?): Session {
  177. if (!WebUtils.isWeb(context)) {
  178. return super.createExposedSession(session, context)
  179. }
  180. val request = WebUtils.getRequest(context)
  181. val response = WebUtils.getResponse(context)
  182. val key = WebSessionKey(session.id, request, response)
  183. return DelegatingSession(this, key)
  184. }
  185. override fun createExposedSession(session: Session, key: SessionKey?): Session {
  186. if (!WebUtils.isWeb(key)) {
  187. return super.createExposedSession(session, key)
  188. }
  189. val request = WebUtils.getRequest(key)
  190. val response = WebUtils.getResponse(key)
  191. val sessionKey = WebSessionKey(session.id, request, response)
  192. return DelegatingSession(this, sessionKey)
  193. }
  194. /**
  195. * Stores the Session's ID, usually as a Cookie, to associate with future requests.
  196. *
  197. * @param session the session that was just [created][.createSession].
  198. */
  199. override fun onStart(session: Session, context: SessionContext?) {
  200. super.onStart(session, context)
  201. if (!WebUtils.isHttp(context)) {
  202. log.debug("SessionContext argument is not HTTP compatible or does not have an HTTP request/response " + "pair. No session ID cookie will be set.")
  203. return
  204. }
  205. val request = WebUtils.getHttpRequest(context)
  206. val response = WebUtils.getHttpResponse(context)
  207. if (sessionIdCookieEnabled) {
  208. val sessionId = session.id
  209. storeSessionId(sessionId, request, response)
  210. } else {
  211. log.debug("Session ID cookie is disabled. No cookie has been set for new session with id {}", session!!.id)
  212. }
  213. request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE)
  214. request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, java.lang.Boolean.TRUE)
  215. }
  216. public override fun getSessionId(key: SessionKey): Serializable? {
  217. var id: Serializable? = super.getSessionId(key)
  218. if (id == null && WebUtils.isWeb(key)) {
  219. val request = WebUtils.getRequest(key)
  220. val response = WebUtils.getResponse(key)
  221. id = getSessionId(request, response)
  222. }
  223. return id
  224. }
  225. protected fun getSessionId(request: ServletRequest, response: ServletResponse): Serializable? {
  226. return getReferencedSessionId(request, response)
  227. }
  228. override fun onExpiration(s: Session, ese: ExpiredSessionException?, key: SessionKey?) {
  229. super.onExpiration(s, ese, key)
  230. onInvalidation(key)
  231. }
  232. override fun onInvalidation(session: Session, ise: InvalidSessionException, key: SessionKey) {
  233. super.onInvalidation(session, ise, key)
  234. onInvalidation(key)
  235. }
  236. private fun onInvalidation(key: SessionKey?) {
  237. val request = WebUtils.getRequest(key)
  238. request?.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID)
  239. if (WebUtils.isHttp(key)) {
  240. log.debug("Referenced session was invalid. Removing session ID cookie.")
  241. removeSessionIdCookie(WebUtils.getHttpRequest(key), WebUtils.getHttpResponse(key))
  242. } else {
  243. log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response " + "pair. Session ID cookie will not be removed due to invalidated session.")
  244. }
  245. }
  246. override fun onStop(session: Session, key: SessionKey?) {
  247. super.onStop(session, key)
  248. if (WebUtils.isHttp(key)) {
  249. val request = WebUtils.getHttpRequest(key)
  250. val response = WebUtils.getHttpResponse(key)
  251. log.debug("Session has been stopped (subject logout or explicit stop). Removing session ID cookie.")
  252. removeSessionIdCookie(request, response)
  253. } else {
  254. log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response " + "pair. Session ID cookie will not be removed due to stopped session.")
  255. }
  256. }
  257. /**
  258. * This is a native session manager implementation, so this method returns `false` always.
  259. *
  260. * @return `false` always
  261. * @since 1.2
  262. */
  263. fun isServletContainerSessions(): Boolean {
  264. return false
  265. }
  266. }