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簡(jiǎn)化配置分析總結(jié)
這篇文章主要介紹了詳解SpringBoot簡(jiǎn)化配置分析總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
Java實(shí)現(xiàn)圖片倒影的源碼實(shí)例內(nèi)容
在本篇文章里小編給大家整理的是關(guān)于Java實(shí)現(xiàn)圖片倒影的源碼以及相關(guān)知識(shí)點(diǎn),有需要的朋友們學(xué)習(xí)下。2019-09-09
Java 其中翻轉(zhuǎn)字符串的實(shí)現(xiàn)方法
這篇文章主要介紹了Java 其中翻轉(zhuǎn)字符串的實(shí)現(xiàn)方法,需要的朋友可以參考下2014-02-02
Java常用正則表達(dá)式驗(yàn)證工具類RegexUtils.java
相信大家對(duì)正則表達(dá)式一定都有所了解和研究,這篇文章主要為大家分享了Java 表單注冊(cè)常用正則表達(dá)式驗(yàn)證工具類,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11

