次のコードを実装しようとしていますが、何かが機能していません。コードは次のとおりです。
var session_url = 'http://api_address/api/session_endpoint';
var username = 'user';
var password = 'password';
var credentials = btoa(username + ':' + password);
var basicAuth = 'Basic ' + credentials;
axios.post(session_url, {
headers: { 'Authorization': + basicAuth }
}).then(function(response) {
console.log('Authenticated');
}).catch(function(error) {
console.log('Error on Authentication');
});
401エラーを返しています。 Postmanでそれを行うとき、基本認証を設定するオプションがあります。これらのフィールドに入力しなかった場合も401が返されますが、入力した場合、リクエストは成功します。
私が間違っていることは何ですか?
これを実装する方法のAPIのドキュメントの一部を次に示します。
このサービスは、ヘッダー内の基本認証情報を使用してユーザーセッションを確立します。資格情報はサーバーに対して検証されます。このWebサービスを使用すると、渡されたユーザー資格情報でセッションが作成され、JSESSIONIDが返されます。このJSESSIONIDは、Webサービス呼び出しを行うための後続のリクエストで使用できます。*
基本認証用の「auth」パラメーターがあります。
auth: {
username: 'janedoe',
password: 's00pers3cret'
}
ソース/ドキュメント: https://github.com/mzabriskie/axios
質問内のコードが認証されない理由は、設定ではなくデータオブジェクトで認証を送信しているためです。 axios docs ごとに、post
のrequestメソッドエイリアスは次のとおりです。
axios.post(url [、data [、config]])
したがって、コードが機能するには、データ用の空のオブジェクトを送信する必要があります。
var session_url = 'http://api_address/api/session_endpoint';
var username = 'user';
var password = 'password';
var basicAuth = 'Basic ' + btoa(username + ':' + password);
axios.post(session_url, {}, {
headers: { 'Authorization': + basicAuth }
}).then(function(response) {
console.log('Authenticated');
}).catch(function(error) {
console.log('Error on Authentication');
});
@luschnが言及したauthパラメーターを使用する場合も同様です。次のコードは同等ですが、代わりにauthパラメーターを使用します(空のデータオブジェクトも渡します)。
var session_url = 'http://api_address/api/session_endpoint';
var uname = 'user';
var pass = 'password';
axios.post(session_url, {}, {
auth: {
username: uname,
password: pass
}
}).then(function(response) {
console.log('Authenticated');
}).catch(function(error) {
console.log('Error on Authentication');
});
何らかの理由で、この単純な問題が多くの開発者をブロックしています。私はこの単純なことで何時間も苦労しました。この問題は多くの次元と同じです:
CORS
開発のための私のセットアップは、localhost:8081で実行されているvuejs webpackアプリケーションとlocalhost:8080で実行されているスプリングブートアプリケーションです。したがって、フロントエンドからREST APIを呼び出そうとすると、ブラウザが適切なCORS設定なしでスプリングバックエンドから応答を受け取る方法はありません。 CORSを使用すると、最新のブラウザーにあるクロスドメインスクリプト(XSS)保護を緩和できます。私がこれを理解しているように、ブラウザーはSPAをXSSによる攻撃から保護しています。もちろん、StackOverflowに関するいくつかの回答は、XSS保護を無効にするためにchromeプラグインを追加することを提案しましたが、これは実際に機能します。
バックエンドCORS設定
Spring BootアプリでCORSを設定する方法は次のとおりです。
CorsFilterクラスを追加して、クライアント要求への応答に適切なヘッダーを追加します。 Access-Control-Allow-OriginとAccess-Control-Allow-Headersは、基本認証のために最も重要なものです。
public class CorsFilter implements Filter {
...
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081");
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
**response.setHeader("Access-Control-Allow-Headers", "authorization, Content-Type");**
response.setHeader("Access-Control-Max-Age", "3600");
filterChain.doFilter(servletRequest, servletResponse);
}
...
}
Spring WebSecurityConfigurationAdapterを拡張する構成クラスを追加します。このクラスでは、CORSフィルターを挿入します。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
@Bean
CorsFilter corsFilter() {
CorsFilter filter = new CorsFilter();
return filter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(corsFilter(), SessionManagementFilter.class) //adds your custom CorsFilter
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/api/login")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.authenticationProvider(getProvider());
}
...
}
コントローラにCORSに関連するものを置く必要はありません。
フロントエンド
次に、フロントエンドで、Authorizationヘッダーを使用してaxiosクエリを作成する必要があります。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<p>{{ status }}</p>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
status: ''
},
created: function () {
this.getBackendResource();
},
methods: {
getBackendResource: function () {
this.status = 'Loading...';
var vm = this;
var user = "aUserName";
var pass = "aPassword";
var url = 'http://localhost:8080/api/resource';
var authorizationBasic = window.btoa(user + ':' + pass);
var config = {
"headers": {
"Authorization": "Basic " + authorizationBasic
}
};
axios.get(url, config)
.then(function (response) {
vm.status = response.data[0];
})
.catch(function (error) {
vm.status = 'An error occured.' + error;
})
}
}
})
</script>
</body>
</html>
お役に立てれば。
応答で Strict-Transport-Security ヘッダーを受信しない限り、luschnとpillraviによって提供されるソリューションは正常に機能します。
withCredentialsを追加する:trueはその問題を解決します。
axios.post(session_url, {
withCredentials: true,
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
},{
auth: {
username: "USERNAME",
password: "PASSWORD"
}}).then(function(response) {
console.log('Authenticated');
}).catch(function(error) {
console.log('Error on Authentication');
});
Node.jsでAxiosを使用した例(axios_example.js):
const axios = require('axios');
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
app.get('/search', function(req, res) {
let query = req.query.queryStr;
let url = `https://your.service.org?query=${query}`;
axios({
method:'get',
url,
auth: {
username: 'xxxxxxxxxxxxx',
password: 'xxxxxxxxxxxxx'
}
})
.then(function (response) {
res.send(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
});
var server = app.listen(port);
プロジェクトディレクトリで次のことを確認してください。
npm init
npm install express
npm install axios
node axios_example.js
次に、ブラウザを使用してNode.js REST APIをテストできます:http://localhost:5000/search?queryStr=xxxxxxxxx