A. 怎麼自定義shiro中的過濾器來允許ajax請求後台數據
自定義過濾器:
public class extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
return executeLogin(request, response);
} else {
// 放行 allow them to see the login page ;)
return true;
}
} else {
HttpServletRequest httpRequest = WebUtils.toHttp(request);
if (ShiroFilterUtils.isAjax(httpRequest)) {
HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
httpServletResponse.sendError(ShiroFilterUtils.HTTP_STATUS_SESSION_EXPIRE);
return false;
} else {
saveRequestAndRedirectToLogin(request, response);
}
return false;
}
}
/**
* 判斷ajax請求
* @param request
* @return
*/
boolean isAjax(HttpServletRequest request){
return (request.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals( request.getHeader("X-Requested-With").toString()) ) ;
}
}
封裝ajax
var Error = function () {
return {
// 初始化各個函數及對象
init: function () {
},
// 顯示或者記錄錯誤
displayError: function(response, ajaxOptions, thrownError) {
if (response.status == 404) {// 頁面沒有找到
pageContent.load($("#hdnContextPath").val() + "/page/404.action");
} else if (response.status == 401) {// session過期
SweetAlert.errorSessionExpire();
} else if (response.status == 507) {// 用戶訪問次數太頻繁
SweetAlert.error("您的訪問次數太頻繁, 請過一會再試...");
} else {//其他錯誤
window.location = $("#hdnContextPath").val() + "/page/500.action";
}
console.log(thrownError);
}
};
}();
jQuery(document).ready(function() {
Error.init();
});
JS的引用處如下:
App.blockUI();
$.ajax({
url: $("#hdnContextPath").val() + "/feedback/queryFeedBackDetail.action",
type: "POST",
async: false,
data: {"feedbackId": feedbackId, "userId": userId, "status": status},
success: function(data) {
// 忽略
B. shiro 攔截器formauthenticationfilter這個過濾器什麼情況有作用
springmvc的攔截器是優先順序高於shiro的,shiro就是自定義實現了spring mvc的filter吧,如果足夠牛逼的話是可以不用shiro的,完全可以自己實現安全攔截的
C. 如何正確的使用shiro
從來沒接觸過shiro Java安全框架,突然有一天需要要用用戶登陸驗證和用戶角色許可權的任務,而且是針對shiro 進行整合,開始收到任務,心都有點涼涼的。經過一輪的搜索,感覺沒多大的收獲。很多用戶的角色都是寫在xml配置文件中。覺得太不人性化了,想換個用戶角色還得改xml?我覺得這么強大的框架應該不可能這么狗血的存在。然後認真的看文檔,發現真的是可以直接讀取資料庫的。我把我搭建的流程發布在此。有問題的可以交流交流。我寫的也並不是正確的,只能參考參考。
1.web.xml的配置
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.shiro.ini配置
[main]
[filters]
#自定義realm
shiroAuthorizingRealm = com.frame.security.ShiroAuthorizingRealm
securityManager.realm = $shiroAuthorizingRealm
# 聲明一個自定義的用戶校驗攔截器
= com.frame.security.
# 聲明一個自定義的用戶角色許可權攔截器
= com.frame.security.
#cache
shiroCacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
shiroCacheManager.cacheManagerConfigFile = classpath:ehcache.xml
securityManager.cacheManager = $shiroCacheManager
#session
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.globalSessionTimeout = 1800000
securityManager = org.apache.shiro.web.mgt.DefaultWebSecurityManager
[urls]
/admin/user/login = anon
/admin/user/logout = anon
/admin/user/registered = anon
/admin/** = ,
從shiro.ini配置中可以看出,需要三個文件,分別為ShiroAuthorizingRealm.java(realm文件),.java(自定義用戶登陸驗證文件),(自定義用戶角色許可權文件);
在urls配置中可以看出不需要攔截的url後面加上anon便可,但有先後順序。
緩存是使用ehcache
3.ehcache.xml配置
<cache name="defaultCache" maxElementsInMemory="500"
maxElementsOnDisk="10000000" eternal="true" overflowToDisk="true"
diskSpoolBufferSizeMB="50" />
<cache name="shiro-activeSessionCache" maxElementsInMemory="500"
maxElementsOnDisk="10000000" eternal="true" overflowToDisk="true"
diskSpoolBufferSizeMB="50" />
<cache name="jdbcRealm.authorizationCache" maxElementsInMemory="500"
maxElementsOnDisk="10000000" eternal="true" overflowToDisk="true"
diskSpoolBufferSizeMB="50" />
<cache name="authorization" maxElementsInMemory="500"
timeToLiveSeconds="3600" eternal="false" overflowToDisk="false" />
4.ShiroAuthorizingRealm.java
public class ShiroAuthorizingRealm extends AuthorizingRealm {
private AuthorityService authorityService = FrameContext.getBean(AuthorityService.class);
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("=======doGetAuthenticationInfo=======");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
String username = userToken.getUsername();
String password = String.valueOf(userToken.getPassword());
User user = User..findFirst("select * from m_user where account = ?", username);
if (user != null) {//下面可以做一些登陸的操作,密碼錯誤,用戶狀態等等
if(MD5Encoder.validPassword(password, user.getPassword())==false){
throw new UnknownAccountException();
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
return info;
} else {
return null;
}
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("=======doGetAuthorizationInfo=======");
User user = (User) principals.getPrimaryPrincipal();
if(user!=null){//從資料庫中讀取用戶的角色許可權,
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
List<String> perms = authorityService.getUrlByUser(user);
if(perms!=null&&perms.size()>0){//調用addStringPermissions方法把用戶的許可權信息添加到info中,可以addRoles方法把用戶的角色添加到了info中
info.addStringPermissions(perms);
}
return info;
}
return null;
}
}
5..java
public class extends FormAuthenticationFilter {
private final static Logger log = Logger.getLogger(.class);
private static final String contentType = "application/json; charset=UTF-8";
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpRequest = WebUtils.toHttp(request);
HttpServletResponse httpResponse = WebUtils.toHttp(response);
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
if (log.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
}
return executeLogin(request, response);
} else {
if (log.isTraceEnabled()) {
log.trace("Login page view.");
}
return true;
}
} else {
Result<Object> result = new Result<Object>(false, "401", "沒有授權,請先登錄", null);
renderJson(httpResponse, result);
return false;
}
}
private void renderJson(HttpServletResponse response, Object object) {
String jsonText = JsonKit.toJson(object);
PrintWriter writer = null;
try {
response.setHeader("Pragma", "no-cache"); // HTTP/1.0 caches might not implement Cache-Control and might only implement Pragma: no-cache
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType(contentType);
writer = response.getWriter();
writer.write(jsonText);
writer.flush();
} catch (IOException e) {
throw new RenderException(e);
}
finally {
if (writer != null) {
writer.close();
}
}
}
}
6..java
public class extends {
private static final String contentType = "application/json; charset=UTF-8";
private AuthorityService authorityService = McmsContext.getBean(AuthorityService.class);
@Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
if(getMappedValue(request)!=null){
return super.isAccessAllowed(request, response, getMappedValue(request));
}
return false;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
// TODO Auto-generated method stub
HttpServletRequest httpRequest = WebUtils.toHttp(request);
HttpServletResponse httpResponse = WebUtils.toHttp(response);
String path = httpRequest.getServletPath();
Subject subject = getSubject(request, response);
if (subject.isPermitted(path)) {
return true;
} else {
Result<Object> result = new Result<Object>(false, "401", "抱歉,您沒有該許可權!", null);
renderJson(httpResponse, result);
return false;
}
}
/**
* 得到mappedValue,相當於perms[user:add]中的「user:add」
* @param path
* @return
*/
public String[] getMappedValue(ServletRequest request) {
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getServletPath();
String code = getCodesByPath(path);
if(null == code) {
return null;
}
return new String[]{code};
}
/**
* 根據訪問路徑獲取許可權代碼
* @param path
* @return
*/
public String getCodesByPath(String path) {
User user = (User) SecurityUtils.getSubject().getPrincipal();
String pers = authorityService.getUrlByUserPath(path,user);
return Optional.ofNullable(pers).orElse(null);
}
private void renderJson(HttpServletResponse response, Object object) {
String jsonText = JsonKit.toJson(object);
PrintWriter writer = null;
try {
response.setHeader("Pragma", "no-cache"); // HTTP/1.0 caches might not implement Cache-Control and might only implement Pragma: no-cache
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType(contentType);
writer = response.getWriter();
writer.write(jsonText);
writer.flush();
} catch (IOException e) {
throw new RenderException(e);
}
finally {
if (writer != null) {
writer.close();
}
}
}
}
7.用戶登陸入口
public void login() {
String account = getPara("account");
String password = getPara("password");
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken tokens = new UsernamePasswordToken(account, password);
tokens.setRememberMe(false);
try {
subject.login(tokens);
User user = (User) subject.getPrincipal();
loginSuccess(user);
UserVo userVo = convertToUserVO(user);
renderSucessResult(userVo);
} catch (UnknownAccountException ue) {
tokens.clear();
renderFailedResult("登錄失敗!無效的賬號或密碼!");
} catch (IncorrectCredentialsException ie) {
tokens.clear();
renderFailedResult("用戶已注銷!");
} catch(LockedAccountException le){
tokens.clear();
renderFailedResult("賬號被鎖定!");
} catch (RuntimeException re) {
re.printStackTrace();
tokens.clear();
renderFailedResult("登錄失敗!");
}
}
資料庫可以自己去設計,這里就不提供了。
參照上面的去整合框架,便可以使用了,這樣搭建適合多種框架的整合。
D. springMvc+shiro做許可權管理時為什麼頁面上沒有顯示內容
正常情況是不會出現這樣的,shiro對於靜態資源的處理,不用特殊配置。
只需要在shiroFilter過濾器filterChainDefinitions項中增加一個靜態資源處理規則就可以,例如允許/css/開頭的資源匿名訪問,只需要這樣一句配置就足矣。
/css/** = anon
配置完成後,未登錄就可以在瀏覽器中直接訪問css下的資源,新項目用的shiro,簡單而又實用的許可權框架。
E. shiro過濾器/* = authc把自己寫的都攔截了,走了上面的攔截器後還是會被/*攔截
我也碰到這種情來況了,,自,發現filters.put("authc", filter_Authc());這種方式注入filter的時候,攔截順序會失效,,,要改成new xx()這種方式才可以filters.put("authc", new Filter_Authc());
F. shiro 為什麼 我一加filterchaindefinitionmap 就不工作了
規則的問題,規則有問題,那肯定就不攔截請求處理了。
推薦一套完整的Shiro Demo,免費的。
Shiro介紹文檔:http://www.sojson.com/shiro
Demo已經部署到線上,地址是http://shiro.itboy.net
管理員帳號:admin,密碼:sojson.com 如果密碼錯誤,請用sojson。PS:你可以注冊自己的帳號,然後用管理員賦許可權給你自己的帳號,但是,每20分鍾會把數據初始化一次。建議自己下載源碼,讓Demo跑起來,然後跑的更快。
G. shiro基於form表單的身份驗證過濾器可否配置兩個成功頁面
Shiro的過濾器的配置是結合使用Spring的DelegatingFilterProxy與FactoryBean2種技術來完成自身過濾器的植入的,所版以理解Shiro的過濾器首先權要理解這2者的使用。
DelegatingFilterProxy :
Spring提供的一個簡便的過濾器的處理方案,它將具體的操作交給內部的Filter對象delegate去處理,而這個delegate對象通過Spring IOC容器獲取,這里採用的是Spring的FactoryBean的方式獲取這個對象。
H. springMvc+shiro做許可權管理,頁面上的靜態資源,樣式圖片等沒有出現,用幾種方式過濾試過,還是不行
正常情況是不會出現這樣的,shiro對於靜態資源的處理,不用特殊配置。
只需要在shiroFilter過濾器filterChainDefinitions項中增加一個靜態資源處理規則就可以,例如允許/css/開頭的資源匿名訪問,只需要這樣一句配置就足矣。
/css/** = anon
配置完成後,未登錄就可以在瀏覽器中直接訪問css下的資源,新項目用的shiro,簡單而又實用的許可權框架。
I. Shiro的 rememberMe 功能使用指導為什麼rememberMe設置了沒作用
採用這個解決方案的前提是,你必須自己先實現一個realm,不過這個我相信大家都會實現的,畢竟默認的不是jdbcRealm ,真正的項目都是要查資料庫才能確定用戶是否登錄的。那麼我就假定大家的項目中都有那麼一個負責驗證登錄的 JdbcRealm, 並且是採用用戶名密碼認證的,在 doGetAuthenticationInfo 方法裡面是採用如下的方法來做認證
...
info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());
這個前提條件保證你的principal是username,相信大部分人根據教程做shiro的時候都採用了這種方式
STEP1 復寫 FormAuthenticationFilter 的 isAccessAllowed 方法
做一個新類繼承FormAuthenticationFilter ,並復寫 isAccessAllowed 方法
package com.yqr.jxc.shiro;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import com.yqr.jxc.service.global.GlobalUserService;
public class RememberAuthenticationFilter extends FormAuthenticationFilter {
@Resource(name="globalUserService")
private GlobalUserService globalUserService;
/**
* 這個方法決定了是否能讓用戶登錄
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
Subject subject = getSubject(request, response);
//如果 isAuthenticated 為 false 證明不是登錄過的,同時 isRememberd 為true 證明是沒登陸直接通過記住我功能進來的
if(!subject.isAuthenticated() && subject.isRemembered()){
//獲取session看看是不是空的
Session session = subject.getSession(true);
//隨便拿session的一個屬性來看session當前是否是空的,我用userId,你們的項目可以自行發揮
if(session.getAttribute("userId") == null){
//如果是空的才初始化,否則每次都要初始化,項目得慢死
//這邊根據前面的前提假設,拿到的是username
String username = subject.getPrincipal().toString();
//在這個方法裡面做初始化用戶上下文的事情,比如通過查詢資料庫來設置session值,你們自己發揮
globalUserService.initUserContext(username, subject);
}
}
//這個方法本來只返回 subject.isAuthenticated() 現在我們加上 subject.isRemembered() 讓它同時也兼容remember這種情況
return subject.isAuthenticated() || subject.isRemembered();
}
}
STEP2 設置使用這個新的 AuthenticationFilter (認證過濾器)
如果你用的是spring那麼
<!-- 整合了rememberMe功能的filter -->
<bean id="rememberAuthFilter" class="com.yqr.jxc.shiro.RememberAuthenticationFilter" ></bean>
<!--將之前的 /** = authc 替換成 rememberAuthFilter
...
/** = rememberAuthFilter
...
如果你用的是 ini 文件,那麼
rememberAuthFilter=com.yqr.jxc.shiro.RememberAuthenticationFilter
#將之前的 /** = authc 替換成 rememberAuthFilter
...
/** = rememberAuthFilter
然後重啟項目我們來測試一下,先登錄一次系統,然後直接關掉瀏覽器,然後打開瀏覽器直接輸入系統某個頁面的地址,發現可以直接進去了,session什麼的也設置好了
J. struts2過濾器<url-pattern>/mall/buy_*</url-pattern>為什麼不生效
第三個寫錯了,web.xml中的過濾器不能寫成/buy_*的方式,你如果要想使用這種方式的話,就用struts2的action的通配方式,就可以採用這樣的方式來批量處理
eg: <action name="a_*" class="" method="{1}">
<result>/{1}.jsp</result>
</action>
好像是這么的,建議去看看struts2的通配action