已拦截跨源请求:同源策略禁止读取位于 http://localhost/payment/page 的远程资源。(原因:CORS 头缺少 ‘Access-Control-Allow-Origin’)。
已拦截跨源请求:同源策略禁止读取位于 http://localhost/payment/page 的远程资源。(原因:CORS 请求未能成功)。
Error: Network Error
原因:前后端分离项目中,ajax请求没有携带cookie,所以后台无法通过cookie获取到SESSIONID,从而无法获取到session对象。而shiro的认证与授权都是通过session实现的
解决:
1.前后端需要建立会话机制
通过token的机制建立前端和后端的会话管理机制
1)登录成功后返回token,并以后每次ajax请求都要携带token
contrller
1.登录成功加上
//获取到登录成功存储到系统上下文中的用户名密码,强转成User类型
User principal = (User)subject.getPrincipal();
//将密码设置为null再传给前台
principal.setPassword(null);
//定义一个map集合拿来存储需要返回的值
HashMap<String,Object> map = new HashMap<>();
//将登录成功的对象存入map
map.put("user", principal);
//将sessionId存储到map
map.put("token", subject.getSession().getId());
//将map存到封装好的返回格式工具类中
ajaxResult.setResultObj(map);
2.前端main.js
//发送请求之前 拦截 把token设置到请求头里面
axios.interceptors.request.use(config => {
//获取前台session里面的token
if (sessionStorage.getItem('token')) {
// 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
config.headers['X-TOKEN'] = sessionStorage.getItem('token')
}
console.debug('config',config)
return config
}, error => {
// Do something with request error
Promise.reject(error)
});
3.传统结构项目中,shiro从cookie中读取sessionId以此来维持会话,在前后端分离的项目中,因此需要重写shiro获取sessionId的方式。 * 自定义SessionManager类继承DefaultWebSessionManager类,重写getSessionId方法
public class crmSessionManager extends DefaultWebSessionManager {
private static final String AUTHORIZATION = "X-TOKEN";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
//取到jessionid
String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
HttpServletRequest request1 = (HttpServletRequest) request;
//如果请求头中有 X-TOKEN 则其值为sessionId
if (!StringUtils.isEmpty(id)) {
System.out.println(id+"jjjjjjjjj"+request1.getRequestURI()+request1.getMethod());
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return id;
} else {
//否则按默认规则从cookie取sessionId
return super.getSessionId(request, response);
}
}
}
3.1注入重写方法获取sessionId的对象
<bean id="sessionManager" class="com.edu.zhy.crm.crmSessionManager"/>
<!--shiro的核心对象 realm-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--配置realm-->
<property name="realm" ref="authRealm"/>
<!-- 调用自己获取sessionid的方法-->
<property name="sessionManager" ref="sessionManager"></property>
</bean>
4.自定义shrio身份认证过滤器 继承FormAuthenticationFilter
/*
* 自定义身份认证过滤器
* */
public class MyAuthenticationFilter extends FormAuthenticationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
//如果是OPTIONS请求,直接放行
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String method = httpServletRequest.getMethod();
System.out.println(method);
if("OPTIONS".equalsIgnoreCase(method)){
return true;
}
return super.isAccessAllowed(request, response, mappedValue);
}
配置上自己重写的过滤器
<!-- 配置过滤器-->
bean注入自己重写过滤器
<bean id="authFilter" class="com.edu.zhy.crm.shrio.filter.MyAuthFilter"></bean>
<!--shiro的过滤器配置 web.xml的代理过滤器名称一样-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/s/login"/>
<property name="successUrl" value="/s/index"/>
<property name="unauthorizedUrl" value="/s/unauthorized"/>
<!--使用自定义过滤器-->
<property name="filters">
<map>
<entry key="authFilter" value-ref="authFilter"></entry>
</map>
</property>
<property name="filterChainDefinitions">
<value>
/login = anon
/** /**= myAuthc**/
</value>
</property>
</bean>