Nhiều mã thông báo truy cập Oauth2


13

Tôi có một API sử dụng oAuth2 và các ứng dụng di động của riêng tôi sử dụng API này làm phụ trợ của chúng. Vì người dùng có thể đăng nhập qua nhiều thiết bị (ví dụ: iPhone, iPad, máy tính bảng Android hoặc điện thoại Android) cùng một lúc, tôi cần API để phân biệt giữa mỗi kết nối. Tôi muốn thực hiện điều này thông qua các mã thông báo truy cập riêng biệt: mỗi khách hàng nhận được một mã thông báo truy cập riêng.

Vấn đề là việc triển khai hiện tại mà chúng tôi sử dụng (spring-security-oauth2) tạo ra một khóa duy nhất dựa trên client_id, tên người dùng và phạm vi. Vì vậy, về cơ bản, khi nhận được mã thông báo truy cập, tất cả khách hàng đều nhận được mã thông báo truy cập giống nhau cho cùng một người dùng. Điều này được thực hiện bằng cách sử dụng DefaultAuthenticationKeyGenerator.

Có an toàn khi bỏ qua trình tạo khóa xác thực và chỉ cần tạo mã thông báo truy cập mới trên mỗi yêu cầu từ khách hàng không?


2
bạn có thể sử dụng phạm vi để phân biệt từng khách hàng? tức là cung cấp cho ios một phạm vi "ios", phạm vi "android", máy tính bảng phạm vi "máy tính bảng", v.v. Nhưng cuối cùng tôi đã viết ra cách triển khai TokenService của riêng mình tạo ra một mã thông báo hoàn toàn mới mỗi lần.
Cướp

Tuy nhiên, nói chung, việc triển khai Spring Security OAuth2 hoạt động tốt với tôi (một khi tôi đã thông qua cấu hình XML), nhưng việc quản lý mã thông báo và các đối tượng xác thực là một điểm đau đang diễn ra.
Cướp

2
Tìm kiếm Google cho "DefaultAuthenticationKeyGenerator" đã đưa tôi đến một tệp .java trong thư viện spring-security-oauth trên GitHub. Lớp đó thực hiện AuthenticationKeyGeneratorgiao diện. Bạn có thể tạo triển khai của riêng bạn và sử dụng thay thế?
Greg Burghardt


2
Tôi đồng ý với @Rob bạn có thể đi với devicetype trong yêu cầu như "android", "ios", "web", v.v.
Vikash Rajpurohit

Câu trả lời:


1

Đám mây mùa xuân đã cung cấp hành vi này. Chỉ cần thêm khách hàng khác nhau. Giống như iosAppClient, androidAppClient trong lớp AuthorizationServerConfiguration của bạn.

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
                clients.inMemory().withClient("androidAppclient")
                    .secret("clientsecret")
                    .autoApprove(true)
                    .accessTokenValiditySeconds(120)
                    .authorizedGrantTypes("password")
                    .resourceIds("accountservice")
                    .scopes("read", "write")
                    .and()
                    .withClient("iosappclient")
                    ........

        }

Trong phần phụ trợ, bạn có thể nhận được clientID như sau

clientId = ((OAuth2Authentication) authentication).getOAuth2Request().getClientId();

và thực hiện các hành vi khác nhau dựa trên clientId.


0

Một câu trả lời là mỗi nền tảng ứng dụng là một ứng dụng khách khác nhau, do đó nên có một id khách hàng khác nhau. Một cho ứng dụng iOS, một cho trang web, v.v.

Để phân biệt giữa iPad và iPhone, tôi khuyên bạn không nên dựa vào hệ thống OAuth cho việc này.


0

Tôi đã vấp phải vấn đề tương tự trong khi phát triển phần phụ trợ của mình với Spring Boot và OAuth2. Vấn đề tôi gặp phải là, nếu nhiều thiết bị chia sẻ cùng một mã thông báo, một khi một thiết bị làm mới mã thông báo, thiết bị kia sẽ không biết gì và, câu chuyện dài, cả hai thiết bị được nhập vào mã thông báo làm mới điên cuồng. Giải pháp của tôi là thay thế mặc định AuthenticationKeyGeneratorbằng một triển khai tùy chỉnh ghi đè DefaultAuthenticationKeyGeneratorvà thêm một tham số mới client_instance_idtrong hỗn hợp trình tạo khóa. Các khách hàng di động của tôi sau đó sẽ gửi tham số này phải là duy nhất trên các cài đặt ứng dụng (iOS hoặc Android). Đây không phải là một yêu cầu đặc biệt, vì hầu hết các ứng dụng di động đã theo dõi trường hợp ứng dụng ở một số dạng.

public class EnhancedAuthenticationKeyGenerator extends DefaultAuthenticationKeyGenerator {

    public static final String PARAM_CLIENT_INSTANCE_ID = "client_instance_id";

    private static final String KEY_SUPER_KEY = "super_key";
    private static final String KEY_CLIENT_INSTANCE_ID = PARAM_CLIENT_INSTANCE_ID;

    @Override
    public String extractKey(final OAuth2Authentication authentication) {
        final String superKey = super.extractKey(authentication);

        final OAuth2Request authorizationRequest = authentication.getOAuth2Request();
        final Map<String, String> requestParameters = authorizationRequest.getRequestParameters();

        final String clientInstanceId = requestParameters != null ? requestParameters.get(PARAM_CLIENT_INSTANCE_ID) : null;
        if (clientInstanceId == null || clientInstanceId.length() == 0) {
            return superKey;
        }

        final Map<String, String> values = new LinkedHashMap<>(2);
        values.put(KEY_SUPER_KEY, superKey);
        values.put(KEY_CLIENT_INSTANCE_ID, clientInstanceId);

        return generateKey(values);
    }

}

mà sau đó bạn sẽ tiêm theo cách tương tự:

final JdbcTokenStore tokenStore = new JdbcTokenStore(mDataSource);
tokenStore.setAuthenticationKeyGenerator(new EnhancedAuthenticationKeyGenerator());

Yêu cầu HTTP sau đó sẽ trông giống như thế này

POST /oauth/token HTTP/1.1
Host: {{host}}
Authorization: Basic {{auth_client_basic}}
Content-Type: application/x-www-form-urlencoded

grant_type=password&username={{username}}&password={{password}}&client_instance_id={{instance_id}}

Lợi ích của việc sử dụng phương pháp này là, nếu máy khách không gửi client_instance_id, khóa mặc định sẽ được tạo và nếu một thể hiện được cung cấp, cùng một khóa được trả về mỗi lần cho cùng một thể hiện. Ngoài ra, chìa khóa là nền tảng độc lập. Nhược điểm sẽ là thông báo MD5 (được sử dụng nội bộ) được gọi hai lần.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.