您好,登錄后才能下訂單哦!
用戶A在線,管理員在后臺更改了用戶A信息(資料或權限)之后;用戶A再進行下一步操作時,會被攔截并退出登錄狀態,再登錄才可以執行操作;來確保用戶A的信息同步更新。
前篇:
基于前篇,新增功能:
wyait-manage、wyait-manage-1.2.0源碼都更新了以上功能!
以及新增了springboot項目,開發和線上jdk版本不一致導致項目無法啟動、無法加載的問題的排查及解決思路。
后篇:
github源碼: https://github.com/wyait/manage.git
碼云:https://gitee.com/wyait/manage.git
github對應項目源碼目錄:wyait-manage-1.2.0
碼云對應項目源碼目錄:wyait-manage-1.2.0
使用shiro可能會遇到修改了用戶權限后,沒有立即生效,需要等到用戶重新登錄后才能生效;不能立即同步更新,顯然是不合理的。
【實測無效】!!!
授權方法,是在shiro進行鑒權的時候才能觸發。只是配置了authc/user/anon等,不會觸發;
perms,port,rest,roles,ssl等,會觸發授權方法doGetAuthorizationInfo。
/**
* 清除所有緩存
*/
public void clearCachedAuth(){
this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
}
//清除ehcache中所有用戶權限緩存
RealmSecurityManager rsm = (RealmSecurityManager)SecurityUtils.getSecurityManager();
ShiroRealm authRealm = (ShiroRealm)rsm.getRealms().iterator().next();
authRealm.clearCachedAuth();
實際解決方案參考下文中的方案二!
在系統中,由管理員更改了用戶A信息后,如果用戶A在線,無法及時更新相關的改動;
更新用戶資料、權限等信息,如果該用戶在線,同步更新用戶信息解決方案:
在ShiroRealm中通過SessionDAO拿到所有在線的用戶,
Collection<Session> sessions = sessionDAO.getActiveSessions();
遍歷找到匹配的,根據情況,退出登錄或更新用戶信息:
@Autowired
private SessionDAO sessionDAO;
public void updateShiroUser(String loginName){
Collection<Session> sessions = sessionDAO.getActiveSessions();
for(Session session:sessions){
if(loginName.equals(String.valueOf(session.getAttribute(DefaultSubjeContext.PRINCIPALS_SESSION_KEY))) {
//設置session立即失效,即將其踢出系統
session.setTimeout(0);
//TODO 或更新下用戶信息
break;
}
}
【不推薦理由】
用戶信息新增version版本標記,寫個攔截器,每次請求判斷version是否一致,如有改動,根據情況,退出或更新用戶信息(本文統一做了退出登錄處理,可以結合實際需求做相應調整)。
這個方案,基于樂觀鎖原理實現。同樣可解決動態更新用戶權限的問題。
ALTER TABLE `user`
MODIFY COLUMN `id` int(10) NOT NULL AUTO_INCREMENT FIRST ,
ADD COLUMN `version` int(10) NULL DEFAULT 0 COMMENT '更新版本' AFTER `send_time`;
TODO【詳見源碼】
/**
*
* @項目名稱:wyait-manage
* @類名稱:UserActionInterceptor
* @類描述:判斷用戶信息是否已被后臺更改,并根據更改的情況做對應的處理
* @創建人:wyait
* @創建時間:2018年5月2日 上午9:36:43
* @version:
*/
public class UserActionInterceptor implements HandlerInterceptor {
private static Logger logger = LoggerFactory
.getLogger(UserActionInterceptor.class);
@Autowired
private UserService userService;
... ...
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object obj, Exception e)
throws Exception {
// TODO Auto-generated method stub
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object obj, ModelAndView mv)
throws Exception {
// TODO Auto-generated method stub
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object obj) throws Exception {
// TODO Auto-generated method stub
logger.debug("請求到達后臺方法之前調用(controller之前)");
// 1. SecurityUtils獲取session中的用戶信息
// HttpSession session=request.getSession();
User user = (User) SecurityUtils.getSubject().getPrincipal();
if (user != null && StringUtils.isNotEmpty(user.getMobile())
&& null != user.getVersion()) {
// 2. 獲取數據庫中的用戶數據
User dataUser = this.userService.findUserByMobile(user.getMobile());
// 3. 對比session中用戶的version和數據庫中的是否一致
if (dataUser != null
&& null != dataUser.getVersion()
&& String.valueOf(user.getVersion()).equals(
String.valueOf(dataUser.getVersion()))) {
// 3.1 一樣,放行
return true;
}else{
// 3.2 不一樣,這里統一做退出登錄處理;//TODO 使用redis緩存用戶權限數據,根據用戶更新、用戶權限更新;做對應的處理。
SecurityUtils.getSubject().logout();
isAjaxResponse(request,response);
}
}
return false;
}
... ...
}
/**
*
* @項目名稱:wyait-manage
* @類名稱:MyWebMvcConfig
* @類描述:自定義靜態資源映射路徑和靜態資源存放路徑
* @創建人:wyait
* @修改時間:2018年5月3日09:55:23
* @version:
*/
@Configuration
public class MyWebMvcConfig extends WebMvcConfigurerAdapter {
/**
* 添加攔截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 路徑根據后期項目的擴展,進行調整
registry.addInterceptor(new UserActionInterceptor())
.addPathPatterns("/user/**", "/auth/**")
.excludePathPatterns("/user/sendMsg", "/user/login");
super.addInterceptors(registry);
}
}
錯誤信息:
java.lang.NullPointerException: null
at com.wyait.manage.interceptor.UserActionInterceptor.preHandle(UserActionInterceptor.java:62) ~[classes/:?]
at org.springframework.web.servlet.HandlerExecutionChain.applyPreHandle(HandlerExecutionChain.java:133) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:962) ~[spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE]
userService對象為null,無法注入UserService。
@Autowired
private UserService userService;
@Configuration
public class MyWebMvcConfig extends WebMvcConfigurerAdapter {
/**
*
* @描述:在Spring添加攔截器之前先創建攔截器對象,這樣就能在Spring映射這個攔截器前,把攔截器中的依賴注入的對象給初始化完成了。
* </br>避免攔截器中注入的對象為null問題。
* @創建人:wyait
* @創建時間:2018年5月3日 上午10:07:36
* @return
*/
@Bean
public UserActionInterceptor userActionInterceptor(){
return new UserActionInterceptor();
}
/**
* 添加攔截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 路徑根據后期項目的擴展,進行調整
registry.addInterceptor(userActionInterceptor())
.addPathPatterns("/user/**", "/auth/**")
.excludePathPatterns("/user/sendMsg", "/user/login");
super.addInterceptors(registry);
}
}
分布式或集群的時候,需要解決session共享問題;相關的方案有:session持久化、redis或其他中間件、nginx的ip_hash、cookie實現、服務器間Session同步等;這時候處理動態更新用戶信息,需要結合實際情況而定;
后期會更新redis版本。
linux 6.* 系統
jdk 1.7
tomcat 7.*
maven 3.3.3
五月 08, 2018 11:49:23 上午 org.apache.catalina.startup.TaglibUriRule body
信息: TLD skipped. URI: http://shiro.apache.org/tags is already defined
五月 08, 2018 11:49:23 上午 org.apache.catalina.startup.TldConfig execute
信息: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
五月 08, 2018 11:51:03 上午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
信息: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [112,917] milliseconds.
五月 08, 2018 11:51:03 上午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deployment of web application directory /usr/tools/tomcat-9190/webapps/ROOT has finished in 117,517 ms
五月 08, 2018 11:51:03 上午 org.apache.catalina.startup.Catalina start
信息: Server startup in 117563 ms
五月 08, 2018 11:51:37 上午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
信息: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [134,439] milliseconds.
...
無明顯錯誤,但是項目沒有加載成功,訪問是404.
At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
對比本地tomcat7和線上tomcat7啟動,會出現tomcat7和8版本沖突問題,本地解決了,線上依舊啟動不成功;再百度、google方案,大致是tomcat版本問題而打印的日志信息,按照搜索的方案配置,均未解決。
考慮應該是環境配置的版本不一致導致的項目無法加載啟動成功,確認并排查下開發、測試、線上的jdk、tomcat等版本是否一致。
java -version
jdk 1.8
java -v
jdk 1.7
這就是導致項目在linux系統啟動不起來的原因:開發和線上的jdk版本不一致!!!
將windows的jdk版本切換為jdk1.7,重新打開新的dos窗口:java -version;jdk顯示為1.7.*。版本切換成功!
...
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.
1:compile (default-compile) on project wyait-manage: Fatal error compiling: 無效的
目標發行版: 1.8 -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e swit
ch.
...
<!--
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
-->
注釋掉這一段maven指定jdk為1.8版本的配置;重新打包,成功!
開發過程中,要確保開發、測試、線上配置的環境(jdk、maven、tomcat等開發依賴的環境支持)保持一致。避免出現由于開發環境中的版本不一致而出現問題,導致項目上線出問題和延遲項目上線時間!
前篇:
后篇:
項目源碼:(包含數據庫源碼)
github源碼: https://github.com/wyait/manage.git
碼云:https://gitee.com/wyait/manage.git
github對應項目源碼目錄:wyait-manage-1.2.0
碼云對應項目源碼目錄:wyait-manage-1.2.0
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。