项目登录流程如下
用户进入前端登录界面,输入账号密码等,输入完成之后前端发送请求到后端(拦截器不会拦截登录请求),后端验证账号密码等成功之后生成Token并存储到数据库,数据库中包含该Token过期时间,然后返回生成的Token到前端。
前端收到Token,表示登录成功,把这个Token存储本地。然后跳转到用户中心页面,用户中心页面在ajax的请求头中带上Token,跟随请求用户数据接口一起带到后端。
后端通过拦截器拦截到这个请求,去判断这个Token是否有效,有效就放过去做他该做的事情,无效就抛出异常。
跨域配置
先说一下这个前后分离的项目,已经配置过跨域这些问题。我这里后端WebMvcConfig配置的方式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | import com.zdyl.devicemanagement.interceptor.AccessInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Resource private WebServerConfig webServerConfig; @Bean public AccessInterceptor getAccessInterceptor() { return new AccessInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry) { List<String> excludeUrl = new ArrayList<>(); excludeUrl.add( "/error" ); excludeUrl.add( "/v1/zdyl/downloadFile" ); excludeUrl.add( "/v1/zdyl/lcoStation/qrcode/**" ); excludeUrl.add( "/devicemanagement/images/**/*" ); excludeUrl.add( "/upgrade/**" ); excludeUrl.add( "/v1/zdyl/login/**" ); excludeUrl.add( "/NewsImage/**" ); excludeUrl.add( "/v1/zdyl/equipment/alarm/toExcel/test" ); excludeUrl.add( "/v1/zdyl/deviceMonitoring/get/alarm/toExcel/**" ); registry.addInterceptor(getAccessInterceptor()).addPathPatterns( "/**" ) .excludePathPatterns(excludeUrl); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { List<String> locations = new ArrayList<String>(); locations.add( "classpath:/META-INF/resources/" ); locations.add( "classpath:/resources/" ); locations.add( "classpath:/public/" ); locations.add( "file:" + webServerConfig.getUploadFileLocation()); locations.add( "file:" + webServerConfig.getPicpath()); locations.add( "file:" + webServerConfig.getProjectsource()); String[] myArray = new String[locations.size()]; registry.addResourceHandler( "/**" ).addResourceLocations(locations.toArray(myArray)); } @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials( true ); config.addAllowedOrigin( "*" ); config.addAllowedHeader( "*" ); config.addAllowedMethod( "*" ); source.registerCorsConfiguration( "/**" , config); return new CorsFilter(source); } @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping( "/**" ) .allowedHeaders( "*" ) .allowCredentials( true ) .allowedOrigins( "*" ) .allowedMethods( "POST" , "GET" , "DELETE" , "PUT" , "OPTIONS" ) .maxAge( 3600 ); } } |
前端每次发送请求也都有在ajax里面设置xhrFields:{withCredentials: true}属性。
拦截器代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.zdyl.devicemanagement.common.exception.RRException; import com.zdyl.devicemanagement.common.utils.AccountNumber; import com.zdyl.devicemanagement.common.utils.RedisSavePrefix; import com.zdyl.devicemanagement.common.utils.RedisUtils; import com.zdyl.devicemanagement.common.utils.SystemConstants; import com.zdyl.devicemanagement.entity.LcoUsers; import com.zdyl.devicemanagement.entity.Login; import com.zdyl.devicemanagement.service.LcoUsersService; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Date; @Slf4j public class AccessInterceptor extends HandlerInterceptorAdapter { @Resource private RedisUtils redisUtils; @Resource private LcoUsersService lcoUsersService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info( "------------------------AccessInterceptor-------------------------" ); if (request.getMethod().equals(RequestMethod.OPTIONS.name())) { return super .preHandle(request, response, handler); } //获取请求token,如果token不存在,直接返回401 String token = getRequestToken(request); String loginId = getRequestloginId(request); if (StringUtils.isEmpty(token)) { throw new RRException( "token为空" , 401 ); } if (StringUtils.isEmpty(loginId)) { throw new RRException( "loginId为空" , 401 ); } Object users = redisUtils.getObject(redisUtils.getKey(RedisSavePrefix.Login, loginId), AccountNumber.loginDataBase); if (users == null ) { throw new RRException( "用户尚未登录" , 401 ); } Login loginUser = JSONObject.parseObject(JSON.toJSONString(users), Login. class ); if (!loginUser.getToken().equals(token)) { throw new RRException( "token不匹配" , 401 ); } Date loginTime = loginUser.getLoginTime(); long exitTime = loginTime.getTime() / 1000 + 7200 ; long time = new Date().getTime(); long nowTime = new Date().getTime() / 1000 ; if (nowTime > exitTime) { throw new RRException( "token已过期!" , 401 ); } QueryWrapper<LcoUsers> lcoUsersQueryWrapper = new QueryWrapper<>(); lcoUsersQueryWrapper.eq( "phone" , loginUser.getLoginID()); LcoUsers lcoUsers = lcoUsersService.getOne(lcoUsersQueryWrapper); request.setAttribute(SystemConstants.CURRENTUSER, lcoUsers); return super .preHandle(request, response, handler); } /** * 获取请求的token */ private String getRequestToken(HttpServletRequest httpRequest) { //从header中获取token String host = httpRequest.getHeader( "token" ); //如果header中不存在token,则从参数中获取token if (StringUtils.isEmpty(host)) { host = httpRequest.getParameter( "token" ); } // if (StringUtils.isEmpty(host)) { // Cookie[] cks = httpRequest.getCookies(); // for (Cookie cookie : cks) { // if (cookie.getName().equals("yzjjwt")) { // host = cookie.getValue(); // return host; // } // } // } return host; } /** * 获取请求的loginId */ private String getRequestloginId(HttpServletRequest httpRequest) { //从header中获取token String loginId = httpRequest.getHeader( "loginId" ); //如果header中不存在token,则从参数中获取token if (StringUtils.isEmpty(loginId)) { loginId = httpRequest.getParameter( "loginId" ); } // if (StringUtils.isEmpty(loginId)) { // Cookie[] cks = httpRequest.getCookies(); // for (Cookie cookie : cks) { // if (cookie.getName().equals("yzjjwt")) { // loginId = cookie.getValue(); // return loginId; // } // } // } return loginId; } /** * 对跨域提供支持 */ protected boolean addCors(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; httpServletResponse.setHeader( "Access-control-Allow-Origin" , httpServletRequest.getHeader( "Origin" )); httpServletResponse.setHeader( "Access-Control-Allow-Methods" , "GET,POST,OPTIONS,PUT,DELETE" ); httpServletResponse.setHeader( "Access-Control-Allow-Headers" , httpServletRequest.getHeader( "Access-Control-Request-Headers" )); // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态 if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) { httpServletResponse.setStatus(HttpStatus.OK.value()); return false ; } return super .preHandle(request, response); } } |
自定义异常RRException代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | /** * 自定义异常 */ public class RRException extends RuntimeException { private static final long serialVersionUID = 1L; private String message; private String code = "INVALID" ; private int status = 0 ; public RRException(String msg) { super (msg); this .message = msg; } public RRException(String msg, Throwable e) { super (msg, e); this .message = msg; } public RRException(String msg, String code) { super (msg); this .message = msg; this .code = code; } public RRException(String msg, int status) { super (msg); this .message = msg; this .status = status; } public RRException(String msg, String code, Throwable e) { super (msg, e); this .message = msg; this .code = code; } public String getMsg() { return message; } public void setMsg(String msg) { this .message = msg; } public String getCode() { return code; } public void setCode(String code) { this .code = code; } public int getStatus() { return status; } public void setStatus( int status) { this .status = status; } } |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自学编程网。
- 本文固定链接: https://zxbcw.cn/post/192808/
- 转载请注明:必须在正文中标注并保留原文链接
- QQ群: PHP高手阵营官方总群(344148542)
- QQ群: Yii2.0开发(304864863)