1、それはブラウザベースのSSOクッキーのようにプロジェクトを変更
1.1、改訂されたコールバックメソッド、代わりに格納するストアからセッションクッキーに、トークンを取得します
/ ** *コールバックメソッド *認証コードの認証サーバ、および交換トークンを受信します * * @Param コード認証コード * @パラメータ送信要求認証サーバの状態が状態 * / (@GetMapping「/ OAuthの/コールバック」) 公共 ボイド oauthCallback(@RequestParamコード列、文字列の状態、HttpServletRequestのリクエスト、HttpServletResponseの応答)スローIOExceptionが{ 文字列oauthTokenUrl = "http://gateway.caofanqi.cn:9010/token/oauth/token" 。 HttpHeadersヘッダー = 新しいHttpHeaders()。 headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED)。 headers.setBasicAuth( "Webアプリケーション"、 "123456" )。 MultiValueMap <文字列、文字列>のparams = 新しい LinkedMultiValueMap <> (); params.set( "コード" 、コード)。 params.set( "grant_type"、 "authorization_code" ); params.set( "REDIRECT_URI"、 "http://web.caofanqi.cn:9000/oauth/callback" ); HttpEntity <MultiValueMap <文字列、文字列>> httpEntity = 新しい HttpEntity <> (paramsは、ヘッダ); ResponseEntity <TokenInfoDTO> authResult = restTemplate.exchange(oauthTokenUrl、HttpMethod.POST、httpEntity、TokenInfoDTO。クラス)。 log.info( "tokenInfo:{}" 、authResult.getBody()); // セッションにトークン // でrequest.getSession()のsetAttribute( "トークン"、authResult.getBody()のinit())。 ; // クッキーにトークン クッキーaccessTokenCookie = 新しい新しいクッキー( "access_tokenは" 。、authResult.getBody()getAccess_token()); accessTokenCookie.setMaxAge(authResult.getBody()getExpires_in()intValue()。 - 5 )。 accessTokenCookie.setDomain( "caofanqi.cn" ); accessTokenCookie.setPath( "/" ); response.addCookie(accessTokenCookie)。 クッキーrefreshTokenCookie = 新しいクッキー( "refresh_token" 、authResult.getBody()getRefresh_token()); refreshTokenCookie.setMaxAge( 2592000 )。 refreshTokenCookie.setDomain( "caofanqi.cn" ); refreshTokenCookie.setPath( "/" ); response.addCookie(refreshTokenCookie)。 log.info(「状態:{}」、状態); // 記録状態の必要性に基づいて、一般的な経路がログインするとき Response.sendRedirect(「/」)。 }
1.2は、CookieTokenFilterを書き、トークンはクッキーから削除します
/ ** *にクッキー要求ヘッダに抽出されたトークン * * @Author caofanqi * @date 2020年2月6日午前0時34分 * / @ SLF4J @成分 パブリック クラス CookieTokenFilterは延びZuulFilterを{ プライベート残りはテンプレートテンプレート=休む新しい休憩テンプレートを(); @オーバーライド パブリック文字列のfilterType(){ 戻り「プレ」。 } @オーバーライド 公共 INT filterOrder(){ リターン 1 。 } @オーバーライド パブリック ブールshouldFilter(){ 戻り 真。 } @オーバーライド パブリックオブジェクトの実行は、()スローZuulExceptionを{ RequestContextのRequestContextの = RequestContext.getCurrentContext()。 HttpServletResponseの応答 = requestContext.getResponse()。 AccessTokenストリング = getCookie( "access_tokenは" ); IF (StringUtils.isNotBlank(accessTokenは)){ // 値説明満了していない requestContext.addZuulRequestHeader( "認可"、 "BEARER" + accessToken)を、 } 他{ // 使用refresh_tokenリフレッシュトークン 文字列getCookie =( "refresh_token" refreshtoken ); IF (StringUtils.isNotBlank(refreshtoken)){ //は認証トークンサーバ更新する 文字列oauthTokenUrl =「HTTP://gateway.caofanqiを。 CN:9010 /トークン/ OAuthの/トークン」。 HttpHeadersヘッダー = 新しいHttpHeaders()。 headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED)。 headers.setBasicAuth( "Webアプリケーション"、 "123456" )。 MultiValueMap <文字列、文字列>のparams = 新しい LinkedMultiValueMap <> (); params.set( "grant_type"、 "refresh_token" ); params.set( "refresh_token" 、refreshToken)。 HttpEntity <MultiValueMap <文字列、文字列>> httpEntity = 新しい HttpEntity <> (paramsは、ヘッダ); してみてください{ ResponseEntity <TokenInfoDTO> refreshTokenResult = restTemplate.exchange(oauthTokenUrl、HttpMethod.POST、httpEntity、TokenInfoDTO。クラス)。 requestContext.addZuulRequestHeader( "認可"、 "ベアラ" + refreshTokenResult.getBody()getAccess_token()。)。 クッキーaccessTokenCookieは = 新しいクッキー( "access_tokenは" 。、refreshTokenResult.getBody()getAccess_tokenを()); accessTokenCookie.setMaxAge(refreshTokenResult.getBody()getExpires_in()intValue()。 - 5 )。 accessTokenCookie.setDomain( "caofanqi.cn" ); accessTokenCookie.setPath( "/" ); response.addCookie(accessTokenCookie)。 クッキーrefreshTokenCookie = 新しいクッキー( "refresh_token" 、refreshTokenResult.getBody()getRefresh_token()); refreshTokenCookie.setMaxAge( 2592000 )。 refreshTokenCookie.setDomain( "caofanqi.cn" ); refreshTokenCookie.setPath( "/" ); response.addCookie(refreshTokenCookie)。 log.info( "refresh_token ......" )。 } キャッチ(例外E){ // 更新トークン失敗 log.info(「リフレッシュトークン失敗」)。 requestContext.setSendZuulResponse(偽); requestContext.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value())。 requestContext.getResponse()に、setContentType(MediaType.APPLICATION_JSON_VALUE)。 requestContext.setResponseBody( "{\"メッセージ\ ":\"トークンリフレッシュ\不合格"}" )。 } } 他{ //はトークンを更新することができない、期限切れ log.infoを(「refresh_tokenない存在」)。 requestContext.setSendZuulResponse(偽); requestContext.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value())。 requestContext.getResponse()に、setContentType(MediaType.APPLICATION_JSON_VALUE)。 requestContext.setResponseBody( "{\"メッセージ\ ":\"トークンリフレッシュ\不合格"}" )。 } } リターン ヌル。 } / ** * Cookieの値を取得します。 * / プライベートのString getCookie(文字列COOKIENAME){ RequestContextのRequestContextの = RequestContext.getCurrentContext()。 HttpServletRequestのリクエスト = requestContext.getRequest()。 クッキー[]クッキー = request.getCookies()。 以下のため:(クッキークッキークッキー){ 場合(StringUtils.equals(COOKIENAME、cookie.getName())){ リターン; cookie.getValue() } } リターン ヌル。 } }
1.3、承認フィルターMeFilter場所後に、ゲートウェイから取得したユーザのログイン状態を決定します。のでライン上のクライアント・サーバーから直接入手できるベースのセッション、の中で、今、急いセッションでは、クライアントがゲートウェイを取得するために、ユーザーのログイン状態を知りません。
APIの始まりを要求するように構成する前に、ゲートウェイに転送されます
ゲートウェイの設定
ゲートウェイはMeFilterをフィルタリング
/ ** *ユーザーは、現在のユーザ認証するかどうかを判断します * * @Author caofanqi * @date 2020年2月7日午後9時43分 * / @成分 パブリック クラス MeFilterは延びZuulFilterを{ @オーバーライド パブリック文字列のfilterType(){ 戻り「プレ」。 } @オーバーライド 公共 INT filterOrder(){ リターン 6 。 } / ** *処理のみ/ユーザー/私の要求 * / @オーバーライド パブリック ブールshouldFilter(){ RequestContextのRequestContextの = RequestContext.getCurrentContext()。 HttpServletRequestのリクエスト = requestContext.getRequest()。 リターン StringUtils.equals(request.getRequestURI()、 "/ユーザー/私" ); } / ** *私たちは、ユーザ名を入れて判断NOリクエストヘッダは、直接の復帰後、下がるしていきませんがあります * / @オーバーライド パブリックオブジェクトの実行は、()スローZuulExceptionを{ RequestContextのRequestContextの = RequestContext.getCurrentContext()。 文字列のユーザ名。= requestContext.getZuulRequestHeadersは、()( "ユーザー名"を取得します)。 もし(StringUtils.isNotBlank(ユーザ名)){ requestContext.setResponseBody( "{\"ユーザー名\ "\" "+名+" \ "}" )。 } requestContext.setSendZuulResponse(偽); requestContext.setResponseStatusCode(HttpStatus.OK.value())。 requestContext.getResponse()に、setContentType(MediaType.APPLICATION_JSON_VALUE)。 リターン ヌル。 } }
1.4、テストに、各プロジェクトを開始
次のように有効期限が設定
アクセスhttp://web.caofanqi.cn:9000/ 、自動的に、注文情報を取得するための時間間隔は、Webアプリケーションのコンソールプリントは、次のようにランディングページ、着陸にジャンプ
お使いのブラウザのクッキーが次のチェック
1.5は、今そこに問題、クッキー、終了で認証情報があるが、また、クッキーを削除します
//退出 function logout() { $.get("/logout", function () { }); //将浏览器中的cookie也删除 $.removeCookie('access_token', { domain:'caofanqi.cn', path: '/' }); $.removeCookie('refresh_token', { domain:'caofanqi.cn', path: '/' }); //客户端session失效后,将认证服务器session也失效掉,添加重定向url location.href = "http://auth.caofanqi.cn:9020/logout?redirect_uri=http://web.caofanqi.cn:9000"; }
2、基于token的SSO优缺点
2.1、优点:
复杂度低,相对于基于session的SSO来说,只需要做access_token和refresh_token的过期处理。
不占用服务器资源,适合用户量特别大的系统。因为token存在浏览器cookie中,只有cookie中的refresh_token失效时,才会去认证服务器登陆。不需要认证服务器设置有效期很长的session。因为通过token就可以访问微服务。
2.2、缺点:
安全性低:token存在浏览器,有一定的风险。可以使用https,缩短access_token的有效期来防范。
可控性低:token存在浏览器,没办法主动失效掉。
项目源码:https://github.com/caofanqi/study-security/tree/dev-web-sso-token