SpringBoot中shiro過濾器的重寫與配置詳解
問題
遇到問題:在前后端分離跨域訪問的項(xiàng)目中shiro進(jìn)行權(quán)限攔截失效 (即使有正確權(quán)限的訪問也會(huì)被攔截) 時(shí)造成302重定向錯(cuò)誤等問題
報(bào)錯(cuò):Response for preflight is invalid (redirect)
1.302原因:使用ajax訪問后端項(xiàng)目時(shí)無法識(shí)別重定向操作
2.shiro攔截失效原因:跨域訪問時(shí)有一種帶預(yù)檢訪問的跨域,即訪問時(shí)先發(fā)出一條methods為OPTIONS的的訪問,這種訪問不帶cookie等信息。造成shiro誤判斷為無權(quán)限訪問。
3.一般使用的訪問methods都是:get,post,put,delete
解決方案
1.讓shiro不對(duì)預(yù)檢訪問攔截
2. 改變shiro中無權(quán)限,未登錄攔截的重定向,這就需要重寫幾個(gè)過濾器
3. 將重寫的過濾器進(jìn)行配置
實(shí)現(xiàn)代碼
1.重寫shiro 登錄 過濾器
過濾器運(yùn)行機(jī)制:
(1)shiro是否攔截訪問 以 isAccessAllowed返回值為準(zhǔn)
(2)如果isAccessAllowed 方法返回false會(huì)進(jìn)入onAccessDenied方法重定向至 登錄 or 無權(quán)限 頁面
package com.yaoxx.base.shiro;
import java.io.PrintWriter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpStatus;
/**
*
* @version: 1.0
* @since: JDK 1.8.0_91
* @Description:
* 未登錄過濾器,重寫方法為【跨域的預(yù)檢訪問】放行
*/
public class MyAuthenticationFilter extends FormAuthenticationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
boolean allowed = super.isAccessAllowed(request, response, mappedValue);
if (!allowed) {
// 判斷請(qǐng)求是否是options請(qǐng)求
String method = WebUtils.toHttp(request).getMethod();
if (StringUtils.equalsIgnoreCase("OPTIONS", method)) {
return true;
}
}
return allowed;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) { // 判斷是否登錄
if (isLoginSubmission(request, response)) { // 判斷是否為post訪問
return executeLogin(request, response);
} else {
// sessionID已經(jīng)注冊(cè),但是并沒有使用post方式提交
return true;
}
} else {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
/*
* 跨域訪問有時(shí)會(huì)先發(fā)起一條不帶token,不帶cookie的訪問。
* 這就需要我們抓取這條訪問,然后給他通過,否則只要是跨域的訪問都會(huì)因?yàn)槲吹卿浕蛉鄙贆?quán)限而被攔截
* (如果重寫了isAccessAllowed,就無需下面的判斷)
*/
// if (req.getMethod().equals(RequestMethod.OPTIONS.name())) {
// resp.setStatus(HttpStatus.OK.value());
// return true;
// }
/*
* 跨域的第二次請(qǐng)求就是普通情況的request了,在這對(duì)他進(jìn)行攔截
*/
String ajaxHeader = req.getHeader(CustomSessionManager.AUTHORIZATION);
if (StringUtils.isNotBlank(ajaxHeader)) {
// 前端Ajax請(qǐng)求,則不會(huì)重定向
resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setContentType("application/json; charset=utf-8");
resp.setCharacterEncoding("UTF-8");
resp.setStatus(HttpStatus.UNAUTHORIZED.value());//設(shè)置未登錄狀態(tài)碼
PrintWriter out = resp.getWriter();
// Map<String, String> result = new HashMap<>();
// result.put("MESSAGE", "未登錄用戶");
String result = "{"MESSAGE":"未登錄用戶"}";
out.println(result);
out.flush();
out.close();
} else {
// == 如果是普通訪問重定向至shiro配置的登錄頁面 == //
saveRequestAndRedirectToLogin(request, response);
}
}
return false;
}
}
2.重寫role權(quán)限 過濾器
package com.yaoxx.base.shiro;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
/**
*
* @author: yao_x_x
* @since: JDK 1.8.0_91
* @Description: role的過濾器
*/
public class MyAuthorizationFilter extends RolesAuthorizationFilter {
@Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws IOException {
boolean allowed =super.isAccessAllowed(request, response, mappedValue);
if (!allowed) {
String method = WebUtils.toHttp(request).getMethod();
if (StringUtils.equalsIgnoreCase("OPTIONS", method)) {
return true;
}
}
return allowed;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (req.getMethod().equals(RequestMethod.OPTIONS.name())) {
resp.setStatus(HttpStatus.OK.value());
return true;
}
// 前端Ajax請(qǐng)求時(shí)requestHeader里面帶一些參數(shù),用于判斷是否是前端的請(qǐng)求
String ajaxHeader = req.getHeader(CustomSessionManager.AUTHORIZATION);
if (StringUtils.isNotBlank(ajaxHeader)) {
// 前端Ajax請(qǐng)求,則不會(huì)重定向
resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setContentType("application/json; charset=utf-8");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
String result = "{"MESSAGE":"角色,權(quán)限不足"}";
out.println(result);
out.flush();
out.close();
return false;
}
return super.onAccessDenied(request, response);
}
}
3.配置過濾器
@Configuration
public class ShiroConfiguration {
@Autowired
private RoleService roleService;
@Autowired
private PermissionService permissionService;
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager")SecurityManager manager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(manager);
/* 自定義filter注冊(cè) */
Map<String, Filter> filters = bean.getFilters();
filters.put("authc", new MyAuthenticationFilter());
filters.put("roles", new MyAuthorizationFilter());
Map<String, String> filterChainDefinitionMap =new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon");
// filterChainDefinitionMap.put("/*", "authc");
// filterChainDefinitionMap.put("/admin", "authc,roles[ADMIN]");
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return bean;
}
以上就是SpringBoot中shiro過濾器的重寫與配置詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot shiro過濾器重寫配置的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot解決Required?String?parameter?xxx?is?not?prese
這篇文章主要介紹了SpringBoot解決Required?String?parameter?xxx?is?not?present問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
Java中的Semaphore信號(hào)量簡(jiǎn)單使用代碼實(shí)例
這篇文章主要介紹了Java中的Semaphore信號(hào)量簡(jiǎn)單使用代碼實(shí)例,Semaphore是用來保護(hù)一個(gè)或者多個(gè)共享資源的訪問,Semaphore內(nèi)部維護(hù)了一個(gè)計(jì)數(shù)器,其值為可以訪問的共享資源的個(gè)數(shù),一個(gè)線程要訪問共享資源,需要的朋友可以參考下2023-12-12
Java帶復(fù)選框的樹(Java CheckBox Tree)實(shí)現(xiàn)和應(yīng)用
這篇文章主要為大家詳細(xì)介紹了Java帶復(fù)選框的樹實(shí)現(xiàn)和應(yīng)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
SpringCloudGateway使用Skywalking時(shí)日志打印traceId解析
這篇文章主要為大家介紹了SpringCloudGateway使用Skywalking時(shí)日志打印traceId解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
IDEA 顯示Run Dashboard窗口的2種方式(推薦)
這篇文章主要介紹了IDEA 顯示Run Dashboard窗口的2種方式,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Java Socket設(shè)置timeout的幾種常用方式說明
這篇文章主要介紹了Java Socket設(shè)置timeout的幾種常用方式說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11

