You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring应用能否集成Realm Database(ROS)?账号校验与token实现咨询

Integrating Realm Database (ROS) with Spring for Token-Based Authentication

Hey there! Let's walk through how to connect your Spring app to Realm Database (ROS) and set up token generation/validation that relies on your existing user credentials stored in ROS. Based on your scenario, we'll cover two common approaches you can take, along with code snippets to make it concrete.

1. First: Set Up ROS Integration in Spring

First, you need to add the Realm Java SDK to your Spring project to interact with ROS. If you're using Maven, add this dependency to your pom.xml:

<dependency>
    <groupId>io.realm</groupId>
    <artifactId>realm-java</artifactId>
    <version>10.15.1</version> <!-- Use the latest compatible version -->
</dependency>

For Gradle, add this to your build.gradle:

implementation 'io.realm:realm-java:10.15.1'

Next, configure the Realm app instance in Spring to connect to your ROS server. Create a @Configuration class for this:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.realm.Realm;
import io.realm.RealmConfiguration;

@Configuration
public class RealmConfig {

    @Bean
    public Realm realmInstance() {
        RealmConfiguration config = new RealmConfiguration.Builder()
                .appId("your-ros-app-id") // Replace with your ROS app ID
                .baseUrl("https://your-ros-server-url") // Replace with your ROS server URL
                .build();
        Realm.setDefaultConfiguration(config);
        return Realm.getDefaultInstance();
    }
}

2. Approach 1: Validate ROS-Generated Tokens in Spring

If your Android app already logs into ROS and gets a ROS access token, you can have Spring verify this token directly to protect your endpoints. Here's how:

Step 2.1: Create a Token Validation Service

This service checks if the incoming ROS token is valid by querying ROS:

import org.springframework.stereotype.Service;
import io.realm.mongodb.App;
import io.realm.mongodb.AppConfiguration;
import io.realm.mongodb.User;
import io.realm.mongodb.auth.Credentials;
import io.realm.mongodb.auth.JwtCredentials;

@Service
public class RosTokenValidationService {

    private final App rosApp;

    public RosTokenValidationService() {
        AppConfiguration appConfig = new AppConfiguration.Builder("your-ros-app-id")
                .baseUrl("https://your-ros-server-url")
                .build();
        this.rosApp = App.create(appConfig);
    }

    public boolean validateRosToken(String token) {
        try {
            // Authenticate using the ROS JWT token
            User user = rosApp.login(Credentials.jwt(token));
            // If login succeeds, token is valid; you can also check user status
            return user.isLoggedIn();
        } catch (Exception e) {
            // Token is invalid or expired
            return false;
        }
    }
}

Step 2.2: Integrate with Spring Security

Add a custom filter to Spring Security that checks the incoming token in the Authorization header:

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
public class RosTokenAuthenticationFilter extends OncePerRequestFilter {

    private final RosTokenValidationService tokenValidationService;

    public RosTokenAuthenticationFilter(RosTokenValidationService tokenValidationService) {
        this.tokenValidationService = tokenValidationService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }

        String token = authHeader.substring(7);
        if (tokenValidationService.validateRosToken(token)) {
            // Create an authentication object (add user details here if needed)
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                    "ros-user", null, null
            );
            authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authToken);
        }

        filterChain.doFilter(request, response);
    }
}

Then update your Spring Security configuration to use this filter:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final RosTokenAuthenticationFilter rosTokenFilter;

    public SecurityConfig(RosTokenAuthenticationFilter rosTokenFilter) {
        this.rosTokenFilter = rosTokenFilter;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/api/images/**").authenticated()
                        .anyRequest().permitAll()
                )
                .addFilterBefore(rosTokenFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}

3. Approach 2: Spring Generates JWT Tokens After ROS Credential Check

If you want Spring to handle its own JWT tokens (instead of using ROS tokens directly), you can have Android send the username/password to Spring, which then validates against ROS before issuing a JWT.

Step 3.1: Add JWT Dependencies

Add these dependencies to your pom.xml (Maven):

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

Step 3.2: Create ROS Credential Validation Service

This service checks if the username/password matches what's stored in ROS:

import org.springframework.stereotype.Service;
import io.realm.mongodb.App;
import io.realm.mongodb.AppConfiguration;
import io.realm.mongodb.User;
import io.realm.mongodb.auth.Credentials;
import io.realm.mongodb.auth.EmailPasswordCredentials;

@Service
public class RosCredentialValidationService {

    private final App rosApp;

    public RosCredentialValidationService() {
        AppConfiguration appConfig = new AppConfiguration.Builder("your-ros-app-id")
                .baseUrl("https://your-ros-server-url")
                .build();
        this.rosApp = App.create(appConfig);
    }

    public User validateCredentials(String username, String password) {
        try {
            Credentials credentials = Credentials.emailPassword(username, password);
            return rosApp.login(credentials);
        } catch (Exception e) {
            // Invalid credentials or login failed
            return null;
        }
    }
}

Step 3.3: JWT Token Service

Create a service to generate and validate JWT tokens:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Service
public class JwtTokenService {

    private final String SECRET_KEY = "your-secret-key-keep-it-safe"; // Use a secure key in production
    private final long EXPIRATION_TIME = 86400000; // 24 hours

    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }

    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    private Claims extractAllClaims(String token) {
        return Jwts.parserBuilder().setSigningKey(SECRET_KEY).build().parseClaimsJws(token).getBody();
    }

    private Boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }

    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, username);
    }

    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder().setClaims(claims).setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
    }

    public Boolean validateToken(String token, String username) {
        final String extractedUsername = extractUsername(token);
        return (extractedUsername.equals(username) && !isTokenExpired(token));
    }
}

Step 3.4: Login Endpoint and Spring Security Setup

Create a controller to handle login requests:

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AuthController {

    private final RosCredentialValidationService credentialService;
    private final JwtTokenService jwtTokenService;

    public AuthController(RosCredentialValidationService credentialService, JwtTokenService jwtTokenService) {
        this.credentialService = credentialService;
        this.jwtTokenService = jwtTokenService;
    }

    @PostMapping("/api/login")
    public ResponseEntity<String> login(@RequestBody LoginRequest request) {
        var user = credentialService.validateCredentials(request.getUsername(), request.getPassword());
        if (user != null) {
            String token = jwtTokenService.generateToken(user.getEmail());
            return ResponseEntity.ok(token);
        }
        return ResponseEntity.status(401).body("Invalid credentials");
    }

    // DTO for login request
    public static class LoginRequest {
        private String username;
        private String password;

        // Getters and setters
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
    }
}

Then update the Spring Security filter to validate JWT tokens instead:

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtTokenService jwtTokenService;

    public JwtAuthenticationFilter(JwtTokenService jwtTokenService) {
        this.jwtTokenService = jwtTokenService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        String username = null;
        String jwt = null;

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            jwt = authHeader.substring(7);
            username = jwtTokenService.extractUsername(jwt);
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            if (jwtTokenService.validateToken(jwt, username)) {
                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                        username, null, null
                );
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        filterChain.doFilter(request, response);
    }
}

And update the SecurityConfig to use this filter:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final JwtAuthenticationFilter jwtAuthenticationFilter;

    public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {
        this.jwtAuthenticationFilter = jwtAuthenticationFilter;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/api/login").permitAll()
                        .requestMatchers("/api/images/**").authenticated()
                        .anyRequest().permitAll()
                )
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}

Key Notes for Production

  • Secure Secrets: Store your ROS app ID, server URL, and JWT secret key in environment variables (use Spring Boot's application.properties with placeholders or a secrets manager) instead of hardcoding.
  • User Details: For more robust authentication, you can fetch user roles/permissions from ROS and add them to the Spring Security authentication object.
  • Token Expiry: Configure appropriate token expiry times based on your security needs.
  • Error Handling: Add proper exception handling in your services and controllers to return meaningful error responses.

内容的提问来源于stack exchange,提问作者kevingiroux

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:52:48