Tôi cần gửi yêu cầu ủy quyền bằng xác thực cơ bản. Tôi đã thực hiện thành công điều này bằng cách sử dụng jquery. Tuy nhiên, khi tôi gặp lỗi 401, cửa sổ bật lên trình duyệt auth cơ bản được mở và không gọi lại lỗi jquery ajax.
Tôi cần gửi yêu cầu ủy quyền bằng xác thực cơ bản. Tôi đã thực hiện thành công điều này bằng cách sử dụng jquery. Tuy nhiên, khi tôi gặp lỗi 401, cửa sổ bật lên trình duyệt auth cơ bản được mở và không gọi lại lỗi jquery ajax.
Câu trả lời:
Tôi cũng phải đối mặt với vấn đề này gần đây. Vì bạn không thể thay đổi hành vi mặc định của trình duyệt hiển thị popup trong trường hợp của một 401
( cơ bản hoặc tiêu hóa xác thực), có hai cách để sửa lỗi này:
401
. 200
Thay vào đó, hãy trả lại mã và xử lý mã này trong ứng dụng khách jQuery của bạn.Thay đổi phương thức bạn đang sử dụng để ủy quyền thành một giá trị tùy chỉnh trong tiêu đề của bạn. Các trình duyệt sẽ hiển thị cửa sổ bật lên cho Basic và Digest . Bạn phải thay đổi điều này trên cả máy khách và máy chủ.
headers : {
"Authorization" : "BasicCustom"
}
Hãy cũng xem phần này để biết ví dụ về việc sử dụng jQuery với Basic Auth.
<security:http-basic/>
bạn không cần định nghĩa basicAuthenticationFilter
mà nên định nghĩa nó là <security:http-basic entry-point-ref="myBasicAuthenticationEntryPoint"/>
.
401
và WWW-Authenticate:Bearer WWW-Authenticate:NTLM WWW-Authenticate:Negotiate
Bạn có biết tại sao điều đó lại như vậy không
Trả lại mã trạng thái chung 400, sau đó xử lý phía máy khách.
Hoặc bạn có thể giữ 401 và không trả lại tiêu đề WWW-Authenticate, đây thực sự là những gì trình duyệt đang phản hồi với cửa sổ bật lên xác thực. Nếu thiếu tiêu đề WWW-Authenticate, thì trình duyệt sẽ không nhắc nhập thông tin đăng nhập.
res.removeHeader('www-authenticate'); // prevents browser from popping up a basic auth window.
Bạn có thể chặn cửa sổ bật lên xác thực cơ bản với url yêu cầu giống như sau:
https://username:password@example.com/admin/...
Nếu bạn gặp lỗi 401 (tên người dùng hoặc mật khẩu sai), nó sẽ được xử lý chính xác bằng lệnh gọi lại lỗi jquery. Nó có thể gây ra một số vấn đề bảo mật (trong trường hợp giao thức http thay vì https), nhưng nó hoạt động.
UPD: Hỗ trợ giải pháp này sẽ bị xóa trong Chrome 59
https://user:pass@host/
trong M59 vào khoảng tháng 6 năm 2017. Hãy xem bài đăng trên blog chromestatus này để biết thêm thông tin.
Như những người khác đã chỉ ra, cách duy nhất để thay đổi hành vi của trình duyệt là đảm bảo phản hồi không chứa mã trạng thái 401 hoặc nếu có thì không bao gồm WWW-Authenticate: Basic
tiêu đề. Vì việc thay đổi mã trạng thái không phù hợp với ngữ nghĩa và không mong muốn, một cách tiếp cận tốt là loại bỏ WWW-Authenticate
tiêu đề. Nếu bạn không thể hoặc không muốn sửa đổi ứng dụng máy chủ web của mình, bạn luôn có thể cung cấp hoặc ủy quyền nó thông qua Apache (nếu bạn chưa sử dụng Apache).
Đây là cấu hình để Apache viết lại phản hồi để loại bỏ tiêu đề WWW-Authenticate IFF mà yêu cầu chứa tiêu đề X-Requested-With: XMLHttpRequest
(được đặt theo mặc định bởi các khung Javascript chính như JQuery / AngularJS, v.v.) VÀ phản hồi chứa đầu trang WWW-Authenticate: Basic
.
Đã thử nghiệm trên Apache 2.4 (không chắc liệu nó có hoạt động với 2.2 hay không). Điều này phụ thuộc vào mod_headers
mô-đun được cài đặt. (Trên Debian / Ubuntu sudo a2enmod headers
và khởi động lại Apache)
<Location />
# Make sure that if it is an XHR request,
# we don't send back basic authentication header.
# This is to prevent the browser from displaying a basic auth login dialog.
Header unset WWW-Authenticate "expr=req('X-Requested-With') == 'XMLHttpRequest' && resp('WWW-Authenticate') =~ /^Basic/"
</Location>
proxy_hide_header WWW-Authenticate;
Sử dụng X-Request-With: XMLHttpRequest với tiêu đề yêu cầu của bạn. Vì vậy, tiêu đề phản hồi sẽ không chứa WWW-Authenticate: Basic.
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', ("Basic "
.concat(btoa(key))));
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
},
Nếu bạn đang sử dụng Máy chủ IIS, bạn có thể thiết lập Ghi lại URL IIS (v2) để ghi lại WWW-Authentication
tiêu đề thànhNone
trên URL được yêu cầu.
Giá trị bạn muốn thay đổi là response_www_authenticate
.
Nếu bạn cần thêm thông tin, hãy thêm nhận xét và tôi sẽ đăng tệp web.config.
Nếu tiêu đề WWW-Authenticate bị xóa, thì bạn sẽ không nhận được bộ nhớ đệm của thông tin đăng nhập và sẽ không lấy lại tiêu đề Ủy quyền theo yêu cầu. Điều đó có nghĩa là bây giờ bạn sẽ phải nhập thông tin đăng nhập cho mọi yêu cầu mới mà bạn tạo.
Ngoài ra, nếu bạn có thể tùy chỉnh phản hồi máy chủ của mình, bạn có thể trả về 403 Forbidden.
Trình duyệt sẽ không mở cửa sổ bật lên xác thực và lệnh gọi lại jquery sẽ được gọi.
Trong Safari, bạn có thể sử dụng các yêu cầu đồng bộ để tránh trình duyệt hiển thị cửa sổ bật lên. Tất nhiên, yêu cầu đồng bộ chỉ nên được sử dụng trong trường hợp này để kiểm tra thông tin đăng nhập của người dùng ... Bạn có thể sử dụng yêu cầu như vậy trước khi gửi yêu cầu thực sự, điều này có thể gây ra trải nghiệm người dùng không tốt nếu nội dung (được gửi hoặc nhận) khá nặng.
var xmlhttp=new XMLHttpRequest;
xmlhttp.withCredentials=true;
xmlhttp.open("POST",<YOUR UR>,false,username,password);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
Tạo một / url đăng nhập, thay vì chấp nhận các tham số "người dùng" và "mật khẩu" thông qua GET và không yêu cầu xác thực cơ bản. Tại đây, sử dụng php, node, java, bất cứ thứ gì và phân tích cú pháp tệp mật khẩu của bạn và khớp các tham số (người dùng / thẻ) với nó. Nếu có khớp, hãy chuyển hướng đến http: // user: pass@domain.com/ (điều này sẽ đặt thông tin đăng nhập trên trình duyệt của bạn) nếu không, hãy gửi phản hồi 401 (không có tiêu đề WWW-Authenticate).
Từ mặt sau với Spring Boot, tôi đã sử dụng BasicAuthenticationEntryPoint tùy chỉnh:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().authorizeRequests()
...
.antMatchers(PUBLIC_AUTH).permitAll()
.and().httpBasic()
// https://www.baeldung.com/spring-security-basic-authentication
.authenticationEntryPoint(authBasicAuthenticationEntryPoint())
...
@Bean
public BasicAuthenticationEntryPoint authBasicAuthenticationEntryPoint() {
return new BasicAuthenticationEntryPoint() {
{
setRealmName("pirsApp");
}
@Override
public void commence
(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
throws IOException, ServletException {
if (request.getRequestURI().equals(PUBLIC_AUTH)) {
response.sendError(HttpStatus.PRECONDITION_FAILED.value(), "Wrong credentials");
} else {
super.commence(request, response, authEx);
}
}
};
}