竞网做的网站怎么样,网做 网站有哪些,大兴网站开发网站建设价格,wordpress 积分Maxkey单点登录系统集成业务系统应用之后#xff0c;登录界面登录之后不会自动跳转业务系统#xff0c;需要在首页点击相应应用之后#xff0c;才能实现跳转业务系统#xff0c;故以下本人提供解决方法和分析思路。 环境配置
本例使用的是CAS协议实现单点登录
Maxkey 服务… Maxkey单点登录系统集成业务系统应用之后登录界面登录之后不会自动跳转业务系统需要在首页点击相应应用之后才能实现跳转业务系统故以下本人提供解决方法和分析思路。 环境配置
本例使用的是CAS协议实现单点登录
Maxkey 服务端
认证服务器地址端口9527
前段登录界面地址http://localhost:8527/maxkey/#/passport/login
业务系统
server:port: 8989
cas:server-url-prefix: http://localhost:9527/sign/authz/cas/ # 认证地址server-login-url: http://localhost:8527/maxkey/#/passport/login #登录地址client-host-url: http://localhost:8989 #客户端地址# 认证方式默认casvalidation-type: cas3# CAS拦截的URL地址authentication-url-patterns:- /casTest/user
maxkey配置地址如下 CAS 原理简单分析
未登录时流程分析 访问地址 http://localhost:8989/casTest/user AbstractTicketValidationFilter 过滤器拦截请求 public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {if (this.preFilter(servletRequest, servletResponse, filterChain)) {HttpServletRequest request (HttpServletRequest)servletRequest;HttpServletResponse response (HttpServletResponse)servletResponse;//获取请求中的 ticketString ticket this.retrieveTicketFromRequest(request);if (CommonUtils.isNotBlank(ticket)) {//...}//无 ticket则放行进入下一个过滤器filterChain.doFilter(request, response);}}AuthenticationFilter 过滤器拦截请求 public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request (HttpServletRequest)servletRequest;HttpServletResponse response (HttpServletResponse)servletResponse;//判断当前请求需不需要拦截if (this.isRequestUrlExcluded(request)) {this.logger.debug(Request is ignored.);filterChain.doFilter(request, response);} else {HttpSession session request.getSession(false);//重定向之后的请求 session中拿出以上过滤器存入的 assertionAssertion assertion session ! null ? (Assertion)session.getAttribute(_const_cas_assertion_) : null;if (assertion ! null) {filterChain.doFilter(request, response);} else {//无 assertion说明之前过滤器无 ticket校验String serviceUrl this.constructServiceUrl(request, response);String ticket this.retrieveTicketFromRequest(request);boolean wasGatewayed this.gateway this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);if (!CommonUtils.isNotBlank(ticket) !wasGatewayed) {this.logger.debug(no ticket and no assertion found);String modifiedServiceUrl;if (this.gateway) {this.logger.debug(setting gateway attribute in session);modifiedServiceUrl this.gatewayStorage.storeGatewayInformation(request, serviceUrl);} else {modifiedServiceUrl serviceUrl;}this.logger.debug(Constructed service url: {}, modifiedServiceUrl);String urlToRedirectTo CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);this.logger.debug(redirecting to \{}\, urlToRedirectTo);//重定向到配置的登录见面this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);} else {filterChain.doFilter(request, response);}}}}登录后流程分析 访问地址 http://localhost:8989/casTest/user AbstractTicketValidationFilter 过滤器拦截请求 public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {if (this.preFilter(servletRequest, servletResponse, filterChain)) {HttpServletRequest request (HttpServletRequest)servletRequest;HttpServletResponse response (HttpServletResponse)servletResponse;//获取请求中的ticketString ticket this.retrieveTicketFromRequest(request);if (CommonUtils.isNotBlank(ticket)) {this.logger.debug(Attempting to validate ticket: {}, ticket);try {//有ticket时校验并返回 assertion Assertion assertion this.ticketValidator.validate(ticket, this.constructServiceUrl(request, response));this.logger.debug(Successfully authenticated user: {}, assertion.getPrincipal().getName());request.setAttribute(_const_cas_assertion_, assertion);if (this.useSession) {//session中存入 assertionrequest.getSession().setAttribute(_const_cas_assertion_, assertion);}this.onSuccessfulValidation(request, response, assertion);if (this.redirectAfterValidation) {this.logger.debug(Redirecting after successful ticket validation.);//请求之后加上jsessionid并重定向请求response.sendRedirect(this.constructServiceUrl(request, response));return;}} catch (TicketValidationException var8) {this.logger.debug(var8.getMessage(), var8);this.onFailedValidation(request, response);if (this.exceptionOnValidationFailure) {throw new ServletException(var8);}response.sendError(403, var8.getMessage());return;}}filterChain.doFilter(request, response);}}AuthenticationFilter 过滤器拦截请求 public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request (HttpServletRequest)servletRequest;HttpServletResponse response (HttpServletResponse)servletResponse;//判断当前请求需不需要拦截if (this.isRequestUrlExcluded(request)) {this.logger.debug(Request is ignored.);filterChain.doFilter(request, response);} else {HttpSession session request.getSession(false);//重定向之后的请求 session中拿出以上过滤器存入的 assertionAssertion assertion session ! null ? (Assertion)session.getAttribute(_const_cas_assertion_) : null;if (assertion ! null) {//如果存在 assertion说明上个过滤器校验ticket通过请求放行filterChain.doFilter(request, response);} else {//...}}}存在问题
登录之后如果不先点击一次首页应用跳转而是直接地址栏输入 http://localhost:8989/casTest/user 跳转还是会跳转到登录界面无法实现登录之后直接跳转应用业务界面
解决思路和步骤 通过以上 CAS原理分析在以下过滤器位置打个断点发现 ticket为空 而如果通过点击首页应用进行第一次跳转请求是会携带 ticket的 说明问题就出在 ticket所以就得搞清楚ticket是在什么时候设置的 通过截图发现点击应用时会调用跳转以下地址 但是该地址通过项目搜索栏搜索却搜不到所以想别的方法 接着想到点击应用就可以跳转到相应的应用业务系统而maxkey和应用的唯一关联的地方就是以下设置的回调地址说明这个回调地址肯定在服务器中哪个地方有使用来进行跳转 通过查看源码发现这回调地址放在一个 callbackUrl的变量里 接着我们查找整个项目发现 callbackUrl会频繁出现在 CasAuthorizeEndpoint.java 类里 点进去发现以下接口即 /authz/cas/应用id 请求接口该接口会获取应用 callbackUrl并重定向到 /authz/cas/granting 请求地址这就与以上的接口对应上了说明我们分析我找对位置了 Operation(summary CAS页面跳转应用ID认证接口, description 传递参数应用ID,methodGET)
GetMapping(CasConstants.ENDPOINT.ENDPOINT_BASE /{id}) //ENDPOINT_BASEauthz/cas
public ModelAndView authorize( PathVariable(id) String id,HttpServletRequest request,HttpServletResponse response){AppsCasDetails casDetails casDetailsService.getAppDetails(id , true);return buildCasModelAndView(request,response,casDetails,casDetails null ? id : casDetails.getCallbackUrl());
}private ModelAndView buildCasModelAndView( HttpServletRequest request,HttpServletResponse response,AppsCasDetails casDetails,String casService){//...省略//ENDPOINT_SERVICE_TICKET_GRANTINGauthz/cas/grantingModelAndView redirect WebContext.redirect(CasConstants.ENDPOINT.ENDPOINT_SERVICE_TICKET_GRANTING);return redirect;}接着发现该类还有一个接口这个接口就是 /authz/cas/granting 接口该接口进行的操作就是获取 ticket并且设置 ticket那么我们登录完成之后只要也跟这部分功能一样有获取 ticket并设置的操作就能实现自动跳转 RequestMapping(CasConstants.ENDPOINT.ENDPOINT_SERVICE_TICKET_GRANTING) // /authz/cas/granting
public ModelAndView grantingTicket( Principal principal,HttpServletRequest request,HttpServletResponse response){ModelAndView modelAndView new ModelAndView(authorize/cas_sso_submint);AppsCasDetails casDetails (AppsCasDetails)WebContext.getAttribute(CasConstants.PARAMETER.ENDPOINT_CAS_DETAILS);ServiceTicketImpl serviceTicket new ServiceTicketImpl(AuthorizationUtils.getAuthentication(),casDetails);_logger.trace(CAS start create ticket ... );//获取 ticketString ticket ticketServices.createTicket(serviceTicket,casDetails.getExpires());_logger.trace(CAS ticket {} created . , ticket);StringBuffer callbackUrl new StringBuffer(casDetails.getCallbackUrl());if(casDetails.getCallbackUrl().indexOf(?)-1) {callbackUrl.append(?);}if(callbackUrl.indexOf() ! -1 ||callbackUrl.indexOf() ! -1) {callbackUrl.append();}//append ticket 设置ticketcallbackUrl.append(CasConstants.PARAMETER.TICKET).append().append(ticket);callbackUrl.append();//append servicecallbackUrl.append(CasConstants.PARAMETER.SERVICE).append().append(casDetails.getService());//...//重定向到应用业务系统_logger.debug(redirect to CAS Client URL {} , callbackUrl);modelAndView.addObject(callbackUrl, callbackUrl.toString());return modelAndView;
}在该类中有以下两个接口点击应用时通过第二个接口来生成 ticket并设置的而第一个接口为 /authz/cas/login?servicexxx 来实现的那是不是我们在登录完成之后请求该接口就可实现自动转发 Operation(summary CAS页面跳转service认证接口, description 传递参数service,methodGET)
GetMapping(CasConstants.ENDPOINT.ENDPOINT_LOGIN)
public ModelAndView casLogin(RequestParam(valueCasConstants.PARAMETER.SERVICE,requiredfalse) String casService,HttpServletRequest request,HttpServletResponse response){AppsCasDetails casDetails casDetailsService.getAppDetails(casService , true);return buildCasModelAndView(request,response,casDetails,casService);
}Operation(summary CAS页面跳转应用ID认证接口, description 传递参数应用ID,methodGET)
GetMapping(CasConstants.ENDPOINT.ENDPOINT_BASE /{id})
public ModelAndView authorize( PathVariable(id) String id,HttpServletRequest request,HttpServletResponse response){AppsCasDetails casDetails casDetailsService.getAppDetails(id , true);return buildCasModelAndView(request,response,casDetails,casDetails null ? id : casDetails.getCallbackUrl());
}根据以上思路我们在登录完成之后添加以上请求地址测试一下 navigate(authJwt: any) {this.startupService.load().subscribe(() {let url this.tokenService.referrer!.url || /;if (url.includes(/passport)) {url /;}if (localStorage.getItem(CONSTS.REDIRECT_URI) ! null) {this.redirect_uri ${localStorage.getItem(CONSTS.REDIRECT_URI)};localStorage.removeItem(CONSTS.REDIRECT_URI);}let service this.getService(service);//添加请求地址this.redirect_uri http://localhost:9527/sign/authz/cas/login?servicehttp://localhost:8989/casTest/user;if (this.redirect_uri ! ) {console.log(redirect_uri ${this.redirect_uri});location.href this.redirect_uri;}this.router.navigateByUrl(url);});}发现登录之后实现了跳转故我们就可以在以上方法中添加 this.redirect_uri 来实现登录后自动跳转至此分析结束 因为访问业务系统时未登录会跳转回登录界面跳转地址为 http://localhost:8527/maxkey/#/passport/login?servicehttp:%2F%2Flocalhost:8989%2FcasTest2%2Fuser2 我们可以通过获取地址栏的serive来拼接到 this.redirect_uri后这样就可以兼容多应用了记得把 %2F 转换为 /