shiro 拦截未登录的ajax_Shiro是如何拦截未登录请求的(二)

本文介绍了如何使用Shiro解决跨域问题并实现基于token和cookie的身份认证。通过设置CORS响应头及自定义`CustomerWebSessionManager`,允许不同端(如APP、H5)根据`device`标识选择性地使用token或cookie进行身份验证。通过扩展Shiro的会话管理器,实现了在会话创建、失效和销毁时的定制行为,确保了不同调用端的兼容性和安全性。
摘要由CSDN通过智能技术生成

前言

在上一篇文章{% post_link Shiro是如何拦截未登录请求的(一) %}中提到了,我们在实际的项目中采用了基于token的方式来实现用户的身份鉴权,但是由于开发的时候对shiro的内部机制不太了解导致那一块的代码实现不够完善、整洁并且还对业务造成了影响,经过了对shiro源码的跟踪分析之后,我们已经知道shiro是如何拦截未登录请求的了,那么接下来我们开始来针对问题制定相应的解决方案.

解决方案

第一种方案

由于最初在app端是使用传输cookie的方式来实现身份鉴权的,跨域问题也已经解决了,为了尽量不改动已经写好的代码,我们可以想办法来让h5应用也能在跨域的情况下传输cookie,首先服务端在使用cors协议时需要设置响应消息头Access-Control-Allow-Credentials的值为true即允许在ajax访问时携带cookie,客户端方面也需通过js设置withCredentials为true才能真正实现跨域传输cookie.另外为了安全,在cors标准里不允许Access-Control-Allow-Origin设置为*,而是必须指定明确的、与请求网页一致的域名.cookie也依然遵循“同源策略”,只有用目标服务器域名设置的cookie才会上传,而且使用document.cookie也无法读取目标服务器域名下的cookie.接下来我们来看看代码是怎么实现的:

1.我们原先在springboot中关于支持跨域有多种实现方式,我们采用最后的一种:

@Bean

public FilterRegistrationBean corsFilter() {

return new FilterRegistrationBean(new Filter() {

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)

throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) req;

HttpServletResponse response = (HttpServletResponse) res;

String method = request.getMethod();

String origin = request.getHeader("Origin");

if(origin == null) {

origin = request.getHeader("Referer");

}

// this origin value could just as easily have come from a database

response.setHeader("Access-Control-Allow-Origin", origin); // 允许指定域访问跨域资源

//response.setHeader("Access-Control-Allow-Origin", "*");

response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS");

response.setHeader("Access-Control-Max-Age", "3600");

response.setHeader("Access-Control-Allow-Credentials", "true");

response.setHeader("Access-Control-Allow-Headers", "Accept, Origin, X-Requested-With, Content-Type,Last-Modified,device,token");

if ("OPTIONS".equals(method)) {

response.setStatus(HttpStatus.OK.value());

} else {

chain.doFilter(req, res);

}

}

public void init(FilterConfig filterConfig) {

}

public void destroy() {

}

});

}

2.客户端也不再需要在请求头中带上token了,只要登录之后不管调什么接口都会自动带上cookie到后端校验的,代码如下:

$.ajax({

url:'http://localhost:8080/win/api/test/cors',

type:'post',

beforeSend:(xhr)=> {

//xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');

//xhr.setRequestHeader("token", "web_session_key-5ce2ae9c-8f79-4f83-9b47-1510da4b2fb0");

xhr.setRequestHeader("device","APP");

},

xhrFields:{

withCredentials:true,

useDefaultXhrHeader:false

},

corssDomain:true,

success:function(data){

console.log(data);

}

});

这样接口就可以正常返回数据了,控制台也不再报错(注意request header中的cookie).

image.png

第二种方案

从上一篇文章中我们知道shiro是在其默认的会话管理器DefaultWebSessionManager中获取请求携带过来的cookie的,我们可以通过继承这个类来扩展其中相关的代码来实现我们的需求,之前在项目中我们已经扩展过这个类了,当时是为了重写其中定时验证session有效性的部分以便在session失效时做一些数据清理工作,下面贴出的是shiro从cookie中获取sessionid的主要源代码:

@Override

public Serializable getSessionId(SessionKey key) {

Serializable id = super.getSessionId(key);

if (id == null && WebUtils.isWeb(key)) {

ServletRequest request = WebUtils.getRequest(key);

ServletResponse response = WebUtils.getResponse(key);

id = getSessionId(request, response);

}

return id;

}

protected Serializable getSessionId(ServletRequest request, ServletResponse response) {

return getReferencedSessionId(re

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值