ExcelやWordなどのWebブラウザーから外部でリンクをクリックすると、同じブラウザーウィンドウの新しいタブでリンクが開いても、セッションCookieが最初は認識されないことに気付きました。
ブラウザーは最終的にそのCookieを認識することになりますが、ExcelまたはWordからの初期リンクが機能しない理由については困惑しています。さらに難しくするために、リンクをクリックするとOutlookで正常に機能します。
なぜこれが起こっているのか知っていますか?私はZend FrameworkをPHP 5.3。
これは、MS OfficeがHlink.dllコンポーネントを使用して、リンクがOfficeドキュメントまたは他の何かであるかどうかを検索するためです。 MS Officeは、(IE6のHlink.dllコンポーネントを使用して)外部ブラウザの助けを借りずにドキュメント内でリンクされたドキュメントを開くことを期待しています。
セッションCookieがWebサイトを保護している場合、Hlinkはログインページに自然にリダイレクトされ、HTMLページに到達して「理解」できないため、外部ブラウザで開きます。元のURL(予期される動作)ではなく、リダイレクトの結果(302リダイレクトであっても)を開くことに注意してください。
マイクロソフトは、サポートされていないコンポーネント(Hlink.dll)にバグを抱えており、バグを認識する代わりに 頭に返して (使用しているSSOシステム、つまりセッションCookieの欠陥であると確信させようとしています。 )アップグレードを拒否します。 検索機能をオフにする回避策 MS Officeを提供します:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
Office\9.0\Common\Internet\ForceShellExecute:DWORD=1
または、HTTPリダイレクトを回避し、JavascriptリダイレクトまたはMETA REFRESHリダイレクトに変更する(つまり、Hlinkに元のURLのtext/htmlページを取得させ、外部ブラウザーを実行して処理させる)ために、サーバーサイドの回避策を提供します。
この同じ問題があり、Railsを使用しているユーザーを支援するオープンソースgemを作成しました。 https://github.com/spilliton/fix_Microsoft_links
ただし、どのフレームワークでも使用したのと同じアプローチを使用できます。
サンプルコード: https://github.com/spilliton/fix_Microsoft_links/blob/master/lib/fix_Microsoft_links.rb
これはIIS(書き換えルールを使用)
<rule name="WordBypass" enabled="true" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_USER_AGENT}" pattern="Word|Excel|PowerPoint|ms-office" />
</conditions>
<action type="CustomResponse" statusCode="200" statusReason="Refresh" statusDescription="Refresh" />
</rule>
上記のスピリトンの答えに基づいたC#ASP.NETのソリューションを次に示します。 Global.asax.csで、次を追加します。
private static string MSUserAgentsRegex = @"[^\w](Word|Excel|PowerPoint|ms-office)([^\w]|\z)";
protected void Application_OnPostAuthenticateRequest(object sender, EventArgs e)
{
if (System.Text.RegularExpressions.Regex.IsMatch(Request.UserAgent, MSUserAgentsRegex))
{
Response.Write("<html><head><meta http-equiv='refresh' content='0'/></head><body></body></html>");
Response.End();
}
}
VB.NETの修正:
Dim userAgent As String = System.Web.HttpContext.Current.Request.UserAgent
If userAgent.Contains("Word") Or userAgent.Contains("Excel") Or userAgent.Contains("PowerPoint") Or userAgent.Contains("ms-office") Then
System.Web.HttpContext.Current.Response.Clear()
System.Web.HttpContext.Current.Response.Write("<html><head><meta http-equiv='refresh' content='0'/></head><body></body></html>")
System.Web.HttpContext.Current.Response.End()
End If
基本的に、ブラウザにページの更新を強制するため、リクエストはブラウザのユーザーエージェントとすべての正しいCookieとともに受信されます。
PHPソリューション:
これにより、MS製品がリダイレクトを認識できなくなります。したがって、MSは必要なリンクからブラウザーを起動します。
if (isset($_SERVER['HTTP_USER_AGENT']))
{
$http_user_agent = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/Word|Excel|PowerPoint|ms-office/i', $http_user_agent))
{
// Prevent MS office products detecting the upcoming re-direct .. forces them to launch the browser to this link
die();
}
}
..このコードの後にリダイレクト
1.Excel/Wordポイントから http://example.com/from_Excel.php
2.「from_Excel.php」で、セッションを使用するページにリダイレクトします
<script>document.location.href = "http://example.com/page_with_session.php"; </script>
これがWordPressでの私の解決策です。これをテーマのfunctions.phpまたは別のプラグインファイルに追加します。
これは、WPなどのシステムが、ログアウトしようとしたユーザーを、アクセスしようとしたページへのリダイレクトを含むログインページに送信する場合に役立ちます。 Wordはこのページにユーザーを送信していましたが、WPはユーザーが既にログインしている場合を適切に処理していませんでした。その場合、redirect_toの場所にリダイレクトします。
function my_logged_in_redirect_to()
{
global $current_user;
if($current_user->ID && $_REQUEST['redirect_to'])
{
wp_redirect($_REQUEST['redirect_to']);
exit;
}
}
add_action('wp', 'my_logged_in_redirect_to');
彼らがこれを機能と呼んでいるとは信じられない。ただし、Apacheの機能修正は次のとおりです。
RewriteEngine On
# Send a 200 to MS Office so it just hands over control to the browser
# It does not use existing session cookies and would be redirected to the login page otherwise
# https://www.wimpyprogrammer.com/Microsoft-office-link-pre-fetching-and-single-sign-on/
RewriteCond %{HTTP_USER_AGENT} ;\sms-office(\)|;)
RewriteRule .* - [R=200,L]
空の応答の代わりにページ全体が送信されるため、最高のパフォーマンスではないかもしれませんが、このようなidio ^ H ^ H ^ H ^ H機能を修正するためだけに別のApacheモジュールを追加したくありませんでした。
MS WordからURLをクリックすると、TWO Chromeタブが開かれ、開くページにJavaScriptリダイレクトがあります:window.location.href=blabla
サーバー側からデバッグすることで、Chrome以外にOfficeアプリから送信されたリクエストがあることを確認しました。これはとても奇妙です。
しかし、とにかく、リクエストヘッダー「User-Agent」を確認し、Officeアプリに空のページを返すことで、2つのタブの問題が解決されました。それは間違いなく正しいことです!
Excel用のVBA修正を以下に示します。同じ概念をMicrosoft Wordに適用できます。基本的に、コードはExcel内からリンクを起動するのではなく、シェル内からリンクを実行します。コードは次のとおりです。
Private Sub Worksheet_FollowHyperlink(ByVal objLink As Hyperlink)
Application.EnableEvents = False
Dim strAddress As String
strAddress = "Explorer " & objLink.TextToDisplay
Dim dblReturn As Double
dblReturn = Shell(strAddress)
Application.EnableEvents = True
End Sub
いくつかのメモ:
以下のリンクからMicrosoftが提供する修正プログラムを使用してください。 https://support.Microsoft.com/en-us/kb/21815
ASP.NETサイトではこの問題を解決する必要がありましたが、javascript/jQueryのみを使用したかったのです。
var isCoBrowse = ('<%= Session["user"].ToString().ToLower() %>' != '0');
if (isCoBrowse && window.location.href.indexOf('ReturnUrl=') >= 0 && window.location.href.indexOf('dllCheq') == -1) {
//redirect to the ReturnUrl & add dllCheq to the URI
var toRedirect = decodeURIComponent(gup('ReturnUrl', window.location.href)) + '&dllCheq';
window.location = toRedirect;
}
私はgup関数を次から取得しました: RLパラメーターから値を取得する方法?
ドットネットコアミドルウェアを使用した修正の例を次に示します。
public class MicrosoftOfficeLinksHandlingMiddleware
{
private static readonly Regex MsUserAgentsRegex = new Regex(@"[^\w](Word|Excel|PowerPoint|ms-office)([^\w]|\z)");
private readonly RequestDelegate _next;
public MicrosoftOfficeLinksHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
string userAgent = context.Request.Headers["User-Agent"].FirstOrDefault();
if (userAgent != null && MsUserAgentsRegex.IsMatch(userAgent))
{
// just return an empty response to the office agent
return;
}
await _next(context);
}
}
JavaとFilter経由のSpringでこれを回避する方法は次のとおりです。
/**
* To see why this is necessary, check out this page:
* https://support.Microsoft.com/en-gb/help/899927.
*/
public class MicrosoftFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(final HttpServletRequest request,
final HttpServletResponse response,
final FilterChain filterChain) throws ServletException, IOException {
//Serve up a blank page to anything with a Microsoft Office user agent, forcing it to open the
//URL in a browser instead of trying to pre-fetch it, getting redirected to SSO, and losing
//the path of the original link.
if (!request.getHeader("User-Agent").contains("ms-office")) {
filterChain.doFilter(request, response);
}
}
}
/**
* Security configuration.
*/
@Configuration
public class SecurityConfiguration {
@Bean
public FilterRegistrationBean microsoftFilterRegistrationBean() {
FilterRegistrationBean<MicrosoftFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new MicrosoftFilter());
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;
}
}