認証とSSO(V) - SSOトークンに基づいて、

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存在浏览器,没办法主动失效掉。

  跨域问题:cookie只能放在顶级域名下(caofanqi.cn),只有二级域名(web.caofanqi.cn、order.caofanqi.cn)才可以做SSO。如果要与baidu.com做SSO的话,需要同时设置多个cookie。

 

 

项目源码:https://github.com/caofanqi/study-security/tree/dev-web-sso-token

 

おすすめ

転載: www.cnblogs.com/caofanqi/p/12275403.html