Rumah >Java >javaTutorial >Kaedah menulis semula dan mengkonfigurasi penapis shiro dalam SpringBoot

Kaedah menulis semula dan mengkonfigurasi penapis shiro dalam SpringBoot

WBOY
WBOYke hadapan
2023-05-15 10:10:061530semak imbas

Masalah

Menghadapi masalah: Dalam projek yang memisahkan akses merentas domain dari bahagian hadapan dan belakang, pemintasan kebenaran shiro gagal (malah akses dengan kebenaran yang betul akan dipintas), menyebabkan masalah seperti 302 ralat ubah hala
Ralat: Respons untuk prapenerbangan tidak sah (ubah hala)

1.302 Sebab: Operasi ubah hala tidak dapat dikenali apabila menggunakan ajax untuk mengakses projek hujung belakang

2 sebab kegagalan: Apabila mengakses merentas domain Terdapat jenis akses merentas domain dengan akses pra-penerbangan, iaitu, apabila mengakses, akses dengan kaedah OPTIONS pertama kali dikeluarkan Akses ini tidak termasuk kuki dan maklumat lain. Ini menyebabkan Shiro tersilap menilai bahawa akses adalah tanpa kebenaran.

3. Kaedah akses yang biasa digunakan ialah: dapatkan, hantar, letak, padam

Penyelesaian

1. Biarkan shiro tidak memintas akses pra-semak

2. Tukar ubah hala pemintasan yang tidak dibenarkan dan tidak dilog dalam shiro, yang memerlukan penulisan semula beberapa penapis

3 Konfigurasikan penapis yang ditulis semula

Kod pelaksanaan

1

Mekanisme pengendalian penapis:

(1) Sama ada shiro memintas akses adalah berdasarkan nilai pulangan isAccessAllowed

(2) Jika kaedah isAccessAllowed mengembalikan palsu, ia akan memasuki onAccessDenied method dan ubah hala ke log masuk atau halaman yang tidak dibenarkan

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:
* 		未登录过滤器,重写方法为【跨域的预检访问】放行

*/

public class MyAuthenticationFilter extends FormAuthenticationFilter {
   
   @Override
   protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
   	boolean allowed = super.isAccessAllowed(request, response, mappedValue);
   	if (!allowed) {
   		// 判断请求是否是options请求
   		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已经注册,但是并没有使用post方式提交
   			return true;
   		}
   	} else {
   		HttpServletRequest req = (HttpServletRequest) request;
   		HttpServletResponse resp = (HttpServletResponse) response;
   		/*
   		 * 跨域访问有时会先发起一条不带token,不带cookie的访问。
   		 * 这就需要我们抓取这条访问,然后给他通过,否则只要是跨域的访问都会因为未登录或缺少权限而被拦截
   		 * (如果重写了isAccessAllowed,就无需下面的判断)
   		 */
//			if (req.getMethod().equals(RequestMethod.OPTIONS.name())) {
//				resp.setStatus(HttpStatus.OK.value());
//				return true;
//			}
   		/*
   		 * 跨域的第二次请求就是普通情况的request了,在这对他进行拦截
   		 */
   		String ajaxHeader = req.getHeader(CustomSessionManager.AUTHORIZATION);
   		if (StringUtils.isNotBlank(ajaxHeader)) {
   			// 前端Ajax请求,则不会重定向
   			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());//设置未登录状态码
   			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 Tulis semula penapis kebenaran peranan

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请求时requestHeader里面带一些参数,用于判断是否是前端的请求
   	String ajaxHeader = req.getHeader(CustomSessionManager.AUTHORIZATION);
   	if (StringUtils.isNotBlank(ajaxHeader)) {
   		// 前端Ajax请求,则不会重定向
   		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":"角色,权限不足"}";
   		out.println(result);
   		out.flush();
   		out.close();
   		return false;
   	}
   	return super.onAccessDenied(request, response);
   }
}

3

Atas ialah kandungan terperinci Kaedah menulis semula dan mengkonfigurasi penapis shiro dalam SpringBoot. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam
Artikel sebelumnya:Analisis contoh blok kod JavaArtikel seterusnya:Analisis contoh blok kod Java