首先道歉 沒經過充分的測試就發文了 后來在review的時候發現我在map中同一個key塞了倆對象
這樣只有最后添加的有效 在看了shiro相關文檔之后找到了有效的解決方法
文章末尾我會補上Shiro自帶的攔截器相關內容
寫一個Shiro的過濾器 繼承org.apache.shiro.web.filter.authc.UserFilter
import com.zzyk.common.model.vo.Message; import com.alibaba.fastjson.JSON; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authc.UserFilter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class GenericFilter extends UserFilter { @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; resp.setCharacterEncoding("UTF-8"); resp.setHeader("ContentType", "text/html;charset=UTF-8"); String requestedWith = req.getHeader("X-Requested-With"); if ("XMLHttpRequest".equals(requestedWith)) { Message message = new Message(); message.setCode(403); message.setMessage("請登錄后操作"); resp.getWriter().write(JSON.toJSONString(message)); } else { this.saveRequestAndRedirectToLogin(request, response); } return false; } }
Shiro的配置類里面的配置我就全部放出來了 就看一下與這次配置相關的
@Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); factoryBean.setSecurityManager(securityManager); // 設置登錄界面URL factoryBean.setLoginUrl(loginUrl); // 設置未經認證頁面的URL factoryBean.setUnauthorizedUrl(unauthorizedUrl); // 設置登錄成功后跳轉的URL factoryBean.setSuccessUrl(indexUrl); HashMap<String, Filter> filter = new HashMap<>(); filter.put("authc", new GenericFilter()); filter.put("logout", new LogoutFilter()); factoryBean.setFilters(filter); // 需要認證的加到authc里面 // 不需要認證的加到anon里面 HashMap<String, String> filterChain = new HashMap<>(); filterChain.put("/customize/**", "anon"); filterChain.put("/plugins/**", "anon"); filterChain.put("/layuiadmin/**", "anon"); filterChain.put("/favicon.ico", "anon"); filterChain.put("/sys/login", "anon"); filterChain.put("/sys/status", "anon"); filterChain.put("/sys/captcha", "anon"); filterChain.put("/device/notice", "anon"); filterChain.put("/druid/**", "anon"); filterChain.put("/sys/logout", "logout"); filterChain.put("/**", "authc"); factoryBean.setFilterChainDefinitionMap(filterChain); return factoryBean; }
另外不知道為啥我用jquery的ajax發出的請求都沒有X-Requested-With請求頭(郁悶...)
我就包裝了一下jquery的ajax 手動把這個請求頭加上 順便處理了一下跨域問題
function getJson(url, params, method, success) { $.ajax({ url: host + url, data: params, method: method, async: true, dataType: "json", xhrFields: { withCredentials: true }, crossDomain: true, beforeSend: function (xhr) { xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") }, success: function (data) { if (data['code'] == 403) { alert(data['message']); top.location.href = 'login.html' } else { if (success) { success(data); } } }, error: function () { alert('服務器錯誤,請聯系管理員'); } }); }
這樣ajax和網頁請求都能正常處理了
注意一個過濾器名只能配一個過濾器 一個資源可以配多個過濾器名 方法為逗號分割 例如
// 定義過濾器
HashMap<String, Filter> filter = new HashMap<>(); filter.put("authc", new GenericFilter()); filter.put("default", new FormAuthenticationFilter()); filter.put("logout", new LogoutFilter()); factoryBean.setFilters(filter);
// 定義過濾鏈 HashMap<String, String> filterChain = new HashMap<>(); filterChain.put("/**", "authc,default"); factoryBean.setFilterChainDefinitionMap(filterChain);
DefaultFilterChainManager 會默認添加 org.apache.shiro.web.filter.mgt.DefaultFilter 中聲明的攔截器
public enum DefaultFilter { anon(AnonymousFilter.class), authc(FormAuthenticationFilter.class), authcBasic(BasicHttpAuthenticationFilter.class), logout(LogoutFilter.class), noSessionCreation(NoSessionCreationFilter.class), perms(PermissionsAuthorizationFilter.class), port(PortFilter.class), rest(HttpMethodPermissionFilter.class), roles(RolesAuthorizationFilter.class), ssl(SslFilter.class), user(UserFilter.class); }
攔截器說明
默認攔截器名 | 攔截器類 | 說明 | 主要參數 |
身份驗證相關 org.apache.shiro.web.filter.authc | |||
authc | FormAuthenticationFilter | 基於表單的攔截器 |
usernameParam: 用戶名(username) passwordParam: 密碼(password) rememberMeParam: 記住密碼(remember) loginUrl: 登錄頁面("/login.jsp") successUrl: 登錄成功后重定向的頁面 failureKeyAttribute: 登錄失敗后 錯誤信息存儲(shiroLoginFailure) |
authcBasic | BasicHttpAuthenticationFilter | Basic HTTP身份驗證攔截器 就是瀏覽器彈出登錄窗口的那種 |
applicationName: 登錄框顯示的信息(application) |
logout | LogoutFilter | 退出登錄攔截器 | redirectUrl: 退出登錄重定向的頁面("/") |
user | UserFilter | 用戶攔截器 用於驗證用戶是否通過身份驗證 |
|
anon | AnonymousFilter | 匿名攔截器 無需認證即可訪問 | |
授權相關 org.apache.shiro.web.filter.authz | |||
roles | RolesAuthorizationFilter | 角色授權攔截器 | loginUrl: 登錄頁面("/login.jsp") unauthorizedUrl: 未授權跳轉的頁面 |
perms | PermissionsAuthorizationFilter | 權限授權攔截器 | |
未完全實現 1.3.2版本不可用 |
HostFilter | 主機地址攔截器 我調用直接拋異常說暫未實現 |
authorizedIps: 已授權的ip地址 deniedIPS: 已拒絕的ip地址 |
port | PortFilter | 端口攔截器 | port: 允許通過的端口 如果是非指定端口訪問 則重定向到該端口 |
rest | HttpMethodPermissionFilter | rest風格攔截器 根據請求方法構建權限字符串 |
GET=read POST=create PUT=update DELETE=delete HEAD=read TEACE=read OPTIONS=read MKCOL=create |
ssl | SslFilter | SSL攔截器 | 無參數 只允許https請求通過 如果是非http請求會重定向到443端口 |
其他 | |||
org.apache.shiro.web.filter.session | |||
noSessionCreation | NoSessionCreationFilter | 不創建會話(Session)攔截器 調用subject.getSession(false)沒問題 調用subject.getSession(true)會拋異常 DisabledSessionException |
節選自《跟我學SHiro》並重新排版,修改了部分內容