当前位置: 首页 > Web前端 > HTML

用户登录(前后)

时间:2023-03-28 18:13:35 HTML

看完后台登录操作,对整个登录流程有了更深的理解。我个人认为有必要总结一下。下面是整个登录操作的流程图:我们从前台开始:onSubmit(){constusername=this.formGroup.get('username').value;constpassword=this.formGroup.get('password').value;this.teacherService.login(username,password).subscribe(result=>{console.log(result);if(result){this.teacherService.setIsLogin(true);}else{console.log('用户名密码错误');}});}用户在V层输入信息发送给C层,然后调用M层代码login(username:string,password:string):Observable{consturl='http://localhost:8080/老师/登录';返回this.httpClient.post(url,{username,password});}setIsLogin(isLogin:boolean){window.sessionStorage.setItem(this.isLoginCacheKey,this.convertBooleanToString(isLogin));this.isLogin.next(isLogin);}如果后台返回信息为真,则设置缓存isLogin为1;如果后台返回信息为false,则登录失败。前台通过post方法将用户名和密码传给后台。然后会被前端拦截器拦截exportclassAuthTokenInterceptorimplementsHttpInterceptor{intercept(req:HttpRequest,next:HttpHandler):Observable>{constreqClone=req.clone({setHeaders:{'auth-token':CacheService.getAuthToken()}});...返回httpEvent;}));}}privatestaticauthToken:string=sessionStorage.getItem('authToken');staticgetAuthToken(){if(CacheService.authToken===null){返回'';}返回CacheService.authToken;}拦截器会在请求的header中设置token,由sessionStorage缓存。sessionStorage用于临时保存同一窗口(或标签)的数据,关闭窗口或标签后将被删除。然后将数据转发到后台。首先,它会通过后台过滤器检查请求头中的令牌是否有效。如果有效,它将在响应的标头中设置令牌对此令牌。如果无效,会通过UUID.randomUUID().toString()方法重新生成一个token,并将token加入到缓存中,通过装饰器方式将token加入到请求的header中。之后,数据将继续转发。在这其中将从请求的header获得中使用到装饰器模型classHttpServletRequestTokenWrapperextendsHttpServletRequestWrapper{字符串标记;私人HttpServletRequestTokenWrapper(HttpServletRequest请求){超级(请求);//super()可视作调用父类构造函数}publicHttpServletRequestTokenWrapper(HttpServletRequestrequest,Stringtoken){this(request);this.token=令牌;}@OverridepublicStringgetHeader(Stringname){if(TOKEN_KEY.equals(name)){logger.info("令牌设置为"+token);返回this.token;}返回super.getHeader(名称);}}我个人认为装饰器模式相当于新写了一个HttpServletRequest的子类,重写了构造函数,让你可以将token传给对象,然后重写它的getheader方法。如果使用getheader获取token,会返回通过构造函数传入的token。并且按照测试装饰器的说法,作用范围不仅仅在过滤器中,而是适用于整个后台工程,即在其他文件方法中调用getheader("auth-token")也能得到想要的结果。数据继续转发后,会经过后台拦截器,在后台判断用户是否登陆,如果没有登陆,则拦截并以401错误返回前台。字符串url=request.getRequestURI();字符串方法=request.getMethod();System.out.println("请求的地址是"+url+"请求的方法是:"+method);if("OPTIONS".equals(method)){/**请求方式为OPTIONS。浏览器在进行跨域访问时,如果发现请求方法不是get,则会在请求前向请求地址发送options方法,确认后台允许前台发起请求方法,当允许请求后台返回的方法包括POST方法,浏览器会发起请求,否则放弃请求。**/返回真;}//判断请求地址和方法是否与用户登录相同if("/Teacher/login".equals(url)&&"POST".equals(method)){System.out.println("请求address方法匹配登录地址,不拦截");返回真;}//auth-token是否绑定用户StringauthToken=request.getHeader(TokenFilter.TOKEN_KEY);if(this.teacherService.isLogin(authToken)){System.out.println("当前token为登录用户绑定,请勿拦截");返回真;}System.out.println("当前token未绑定登录用户,返回401");//添加到响应提示:用户未登录response.setStatus(401);返回假;}@OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,@NullableModelAndViewmodelAndView)throwsException{logger.info("executioninterceptor)postHandle;}经过拦截器后,请求会被转发到C层中后台,匹配到相应的url和方法后,就会执行相应的登录操作。如果根据传递的用户名和密码验证失败,则直接返回false,如果验证成功,则将当前请求中包含的token绑定到当前登录用户的ID上。并返回真实;令牌绑定到用户ID:this.authTokenTeacherIdHashMap.put(this.request.getHeader("auth-token"),teacher.getId());相应的,如果要判断用户是否登录,只需要判断当前token是否绑定了用户id即可,即:publicbooleanisLogin(StringauthToken){LongteacherId=this.authTokenTeacherIdHashMap.get(authToken);返回teacherId!=null;如果想退出,只需要删除token和用户id的绑定:publicvoidlogout(){StringauthToken=this.request.getHeader("auth-token");logger.info("获取到的auth-token为"+this.request.getHeader("auth-token"));this.authTokenTeacherIdHashMap.remove(authToken);}当后台处理完成并返回结果时,必须经过后台拦截器事后过滤。经过后置过滤,一个完整的响应就完成了。之后需要经过后台过滤器进行事后监控,再将响应发送给前台。响应到达前台后,需要经过前台拦截器更新当前token,才能转发。constreqClone=req.clone({setHeaders:{'auth-token':CacheService.getAuthToken()}});returnnext.handle(reqClone).pipe(map((httpEvent)=>{if(httpEventinstanceofHttpResponse){consthttpResponse=httpEventasHttpResponse;constauthToken=httpResponse.headers.get('auth-token');console.log('Intercept1');//执行一次CacheService.setAuthToken(authToken);}console.log('Intercept2');//执行两次returnhttpEvent;}));这也证明拦截器会处理response,上面就是执行一个请求的执行结果。将响应令牌存储在缓存中以更新当前令牌:staticsetAuthToken(token:string){CacheService.authToken=token;sessionStorage.setItem('authToken',token);至此,整个登录流程就介绍完了。另外:本周我也遇到了一个小问题——钉钉机器人连接失败。钉钉建立后,默认连接成功,执行请求时会调用如下代码://客户端执行(发送)Post请求response=httpClient.execute(httpPost);//从响应模型中获取响应实体HttpEntityresponseEntity=response.getEntity();System.out.println("响应状态为:"+response.getStatusLine());if(responseEntity!=null){if(EntityUtils.toString(responseEntity).substring(11,12).equals("0")){ding.setConnectionStatus(true);}else{ding.setConnectionStatus(false);}即如果得到的响应不符合要求,连接状态会被设置为false。一开始认为是webhook或者secret有问题,但是经过多次验证也没有发现问题,更换其他robot也没有解决问题。这时候想到是电脑时间不对,在访问一些网站的时候,会出现类似如下的错误。连接www.kancloud.cn时出错。OCSPresponse还没有生效(包含futuredate)Errorcode:SEC_ERROR_OCSP_FUTURE_RESPONSE所以我猜测钉钉机器人可能也有这样的机制,然后更改时间重试连接成功。