Shiro+SpringBoot前后端分离中跨域,sessionId,302问题

1.解决跨域
@Configuration
public class CorsConfig {
    public CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); //允许任何域名
        corsConfiguration.addAllowedHeader("*"); //允许任何头
        corsConfiguration.addAllowedMethod("*"); //允许任何方法
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); //注册
        return new CorsFilter(source);
    }
}
2.解决sessionId不一致问题,配置shiro,重写获取sessionId方法
//自定义的 shiro session 缓存管理器,用于跨域等情况下使用 token 进行验证,不依赖于sessionId(在shiroConfig中添加)
@Bean
public DefaultWebSessionManager getDefaultWebSessionManager() {
    MySessionManager defaultWebSessionManager = new MySessionManager();
    defaultWebSessionManager.setSessionDAO(new MemorySessionDAO());
    return defaultWebSessionManager;
}

//shiro 的 session 管理(单独写一个类)
//自定义session规则,实现前后分离,在跨域等情况下使用token 方式进行登录验证才需要,否则没必须使用本类。
//(shiro默认使用 ServletContainerSessionManager 来做 session 管理,它是依赖于浏览器的 cookie 来维护 session 的,调用 storeSessionId  方法保存sesionId 到 cookie中)。
//为了支持无状态会话,我们就需要继承 DefaultWebSessionManager
//自定义生成sessionId 则要实现 SessionIdGenerator

public class MySessionManager extends DefaultWebSessionManager {
    private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";

    public MySessionManager() {
        super();
    }

    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        String id = WebUtils.toHttp(request).getHeader("Access-Token");
        //如果请求头中有 token 则其值为sessionId
        if (!StringUtils.isEmpty(id)) {
            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.解决登录302问题
public class UserAuthenticationFilter extends FormAuthenticationFilter {
    /**
     * 直接过滤可以访问的请求类型
     */
    private static final String REQUET_TYPE = "OPTIONS";

    public UserAuthenticationFilter() {
        super();
    }

    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (((HttpServletRequest) request).getMethod().toUpperCase().equals(REQUET_TYPE)) {
            return true;
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }

    /**
     * 解决302
     * @param request
     * @param response
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if (isLoginRequest(request, response)) {
            if (isLoginSubmission(request, response)) {
                return executeLogin(request, response);
            } else {
                return true;
            }
        }else {
            //解决 WebUtils.toHttp 往返回response写数据跨域问题
            HttpServletRequest req =  WebUtils.toHttp(request);
            String origin = req.getHeader("Origin");
            HttpServletResponse resp = WebUtils.toHttp(response);
            resp.setHeader("Access-Control-Allow-Origin", origin);
            //通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时的 Cookie
            //设置了Allow-Credentials,Allow-Origin就不能为*,需要指明具体的url域
            resp.setHeader("Access-Control-Allow-Credentials", "true");
            // 返回固定的JSON串
            ObjectMapper mapper = new ObjectMapper();
            WebUtils.toHttp(response).setContentType("application/json; charset=utf-8");
            WebUtils.toHttp(response).getWriter().print(mapper.writeValueAsString(100));
            return false;
        }

    }

}
4.解决权限不足302问题
public class UserAuthorizationFilter extends PermissionsAuthorizationFilter {
    /**
     * 根据请求接口路径进行验证
     * @param request
     * @param response
     * @param mappedValue
     * @return
     * @throws IOException
     */
    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
        // 获取接口请求路径
        String servletPath = WebUtils.toHttp(request).getServletPath();
        mappedValue = new String[]{servletPath};
        return super.isAccessAllowed(request, response, mappedValue);
    }

    /**
     * 解决权限不足302问题
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        Subject subject = getSubject(request, response);
        if (subject.getPrincipal() != null) {
            return true;
        } else {

            //解决 WebUtils.toHttp 往返回response写数据跨域问题
            HttpServletRequest req = (HttpServletRequest) request;
            String origin = req.getHeader("Origin");
            HttpServletResponse resp = (HttpServletResponse) response;
            resp.setHeader("Access-Control-Allow-Origin", origin);
            //通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时的 Cookie
            //设置了Allow-Credentials,Allow-Origin就不能为*,需要指明具体的url域
            resp.setHeader("Access-Control-Allow-Credentials", "true");

            WebUtils.toHttp(response).setContentType("application/json; charset=utf-8");
            WebUtils.toHttp(response).getWriter().print("401");
        }
        return false;
    }

}

 参考:https://blog.csdn.net/wmy_0707/article/details/100118329?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-3&spm=1001.2101.3001.4242 

            https://blog.csdn.net/China_hdy/article/details/97154272

posted @ 2021-01-13 17:15  一步一高  阅读(3043)  评论(0编辑  收藏  举报