pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
application.properties
server.port=8080
TestCtrller.java
@RestController public class TestCtrller extends BaseCtrller{ //session失效化-for功能測試 @GetMapping("/invalidateSession") public BaseResult invalidateSession(HttpServletRequest request) { HttpSession session = request.getSession(false); if(session != null && session.getAttribute(SysConsts.Session_Login_Key)!=null) { request.getSession().invalidate(); getServletContext().log("Session已註銷!"); } return new BaseResult(true); } //模擬普通ajax數據請求(待登陸攔截的) @GetMapping("/hello") public BaseResult hello(HttpServletRequest request) { getServletContext().log("登陸session未失效,繼續正常流程!"); return new BaseResult(true, "登陸session未失效,繼續正常流程!"); } //登陸接口 @PostMapping("/login") public BaseResult login(@RequestBody SysUser dto, HttpServletRequest request) { //cookie信息 Cookie[] cookies = request.getCookies(); if(null!=cookies && cookies.length>0) { for(Cookie c:cookies) { System.out.printf("cookieName-%s, cookieValue-%s, cookieAge-%d%n", c.getName(), c.getValue(), c.getMaxAge()); } } /** * session處理 */ //模擬庫存數據 SysUser entity = new SysUser(); entity.setId(1); entity.setPassword("123456"); entity.setUsername("Richard"); entity.setNickname("Richard-管理員"); //驗密 if(entity.getUsername().equals(dto.getUsername()) && entity.getPassword().equals(dto.getPassword())) { if(request.getSession(false) != null) { System.out.println("每次登陸成功改變SessionID!"); request.changeSessionId(); //安全考量,每次登錄成功改變 Session ID,原理:原來的session註銷,拷貝其屬性創建新的session對象 } //新建/刷新session對象 HttpSession session = request.getSession(); System.out.printf("sessionId: %s%n", session.getId()); session.setAttribute(SysConsts.Session_Login_Key, entity); session.setAttribute(SysConsts.Session_UserId, entity.getId()); session.setAttribute(SysConsts.Session_Username, entity.getUsername()); session.setAttribute(SysConsts.Session_Nickname, entity.getNickname()); entity.setId(null); //敏感數據不返回前端 entity.setPassword(null); return new BaseResult(entity); } else { return new BaseResult(ErrorEnum.Login_Incorrect); } } }
MyWebMvcConfig.java
@Configuration public class MyWebMvcConfig implements WebMvcConfigurer{ //全局跨域配置 @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") //添加映射路徑 .allowedOrigins("http://localhost:8081") //放行哪些原始域 .allowedMethods("*") //放行哪些原始域(請求方式) //"GET","POST", "PUT", "DELETE", "OPTIONS" .allowedHeaders("*") //放行哪些原始域(頭部信息) .allowCredentials(true) //是否發送Cookie信息 // .exposedHeaders("access-control-allow-headers", // "access-control-allow-methods", // "access-control-allow-origin", // "access-control-max-age", // "X-Frame-Options") //暴露哪些頭部信息(由於跨域訪問默認不能獲取所有頭部信息) .maxAge(1800); } //註冊攔截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyLoginInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/login") .excludePathPatterns("/invalidateSession"); //.excludePathPatterns("/static/**"); } }
MyLoginInterceptor.java
public class MyLoginInterceptor implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { request.getServletContext().log("MyLoginInterceptor preHandle"); HttpSession session = request.getSession(); request.getServletContext().log("sessionID: " + session.getId()); Optional<Object> token = Optional.ofNullable(session.getAttribute(SysConsts.Session_Login_Key)); if(token.isPresent()) { //not null request.getServletContext().log("登陸session未失效,繼續正常流程!"); } else { request.getServletContext().log(ErrorEnum.Login_Session_Out.msg()); // Enumeration<String> enumHeader = request.getHeaderNames(); // while(enumHeader.hasMoreElements()) { // String name = enumHeader.nextElement(); // String value = request.getHeader(name); // request.getServletContext().log("headerName: " + name + " headerValue: " + value); // } //還沒有弄清楚爲啥全局異常處理返回的響應中沒有跨域須要的header,因而乎強行設置響應header達到目的 XD.. //但願有答案的夥伴能夠留言賜教 response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin")); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=utf-8"); // PrintWriter writer = response.getWriter(); // writer.print(new BaseResult(ErrorEnum.Login_Session_Out)); // return false; throw new BusinessException(ErrorEnum.Login_Session_Out); } return true; } }
MyCtrllerAdvice.java
@ControllerAdvice( basePackages = {"com.**.web.*"}, annotations = {Controller.class, RestController.class}) public class MyCtrllerAdvice { //全局異常處理-ajax-json @ExceptionHandler(value=Exception.class) @ResponseBody public BaseResult exceptionForAjax(Exception ex) { if(ex instanceof BusinessException) { return new BaseResult((BusinessException)ex); }else { return new BaseResult(ex.getCause()==null?ex.getMessage():ex.getCause().getMessage()); } } }
router/index.js
import Vue from 'vue' import Router from 'vue-router' import Home from '@/components/Home' import Login from '@/components/Login' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'Login', component: Login }, { path: '/home', name: 'Home', component: Home } ] })
config/index.js
module.exports = { dev: { // Paths assetsSubDirectory: 'static', assetsPublicPath: '/', proxyTable: {}, // Various Dev Server settings host: 'localhost', // can be overwritten by process.env.HOST port: 8081, // can be overwritten by //...
src/main.js
import axios from 'axios' axios.defaults.baseURL = 'http://localhost:8080' //axios.defaults.timeout = 3000 axios.defaults.withCredentials = true //請求發送cookie // 添加請求攔截器 axios.interceptors.request.use(function (config) { // 在發送請求以前作些什麼 console.log('in interceptor, request config: ', config); return config; }, function (error) { // 對請求錯誤作些什麼 return Promise.reject(error); }); // 添加響應攔截器 axios.interceptors.response.use(function (response) { // 對響應數據作點什麼 console.log('in interceptor, response: ', response); if(!response.data.success){ console.log('errCode:', response.data.errCode, 'errMsg:', response.data.errMsg); Message({type:'error',message:response.data.errMsg}); let code = response.data.errCode; if('login02'==code){ //登陸session失效 //window.location.href = '/'; console.log('before to login, current route path:', router.currentRoute.path); router.push({path:'/', query:{redirect:router.currentRoute.path}}); } } return response; }, function (error) { // 對響應錯誤作點什麼 console.log('in interceptor, error: ', error); Message({showClose: true, message: error, type: 'error'}); return Promise.reject(error); });
sessionStorage
初級版)src/main.js
//URL跳轉(變化)攔截 router.beforeEach((to, from, next) => { //console.log(to, from, next) // if(to.name=='Login'){ //自己就是登陸頁,就不用驗證登陸session了 next() return } if(!sessionStorage.getItem('username')){ //沒有登陸/登陸過時 next({path:'/', query:{redirect:to.path}}) }else{ next() } })
header
console
中提示的響應頭:XMLHttpRequest cannot load http://localhost:8080/hello. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access. //PS:查看network能夠看到請求是200的,可是前端不能拿到響應
後端強行塞入指定響應頭能夠達到目的的(見後端攔截器),這樣作不優雅,緣由還不知道 XD..
@20190808 更新
真正上線,代理轉發交給nginx,則不會採用後端配置方式,也就不會有這個問題。html