sql >> データベース >  >> NoSQL >> MongoDB

SpringSecurityとMongoDBによる認証

    実行中の認証をリアルタイムで可視化することは、非常に困難です。流れ。

    プロセスの一部を完全に隠すことができます。完全な承認プロセスでリモートOAuth本番サーバーからのリダイレクトが必要な場合は、すべてのデバッグ作業を本番サーバーで行う必要があります。

    これをローカルでデバッグすることは事実上不可能です。正確な状態を再現する方法はなく、内部で実際に何が起こっているかを検査する方法もありません。理想的ではありません。

    この種の課題を認識して、コードレベルの情報で複雑なフローを理解できるように、リアルタイムの本番デバッグツールであるLightrunを構築しました。ログを追加し、スナップショット(仮想ブレークポイント)を取得し、リモートデバッガーを使用せずに、実行中のサービスを停止せずにメトリックを計測します。最も重要なのは、リアルタイムで副作用なしで

    この5分間のチュートリアルで詳細をご覧ください Lightrunを使用したこれらの種類のシナリオのデバッグに焦点を当てています:

    >>Lightrunを使用した認証と承認のデバッグ

    1。概要

    Spring Securityは、データベースや UserDetailService など、さまざまな認証システムを提供しています。 。

    JPA永続レイヤーを使用する代わりに、たとえば、MongoDBリポジトリを使用することもできます。このチュートリアルでは、SpringSecurityとMongoDBを使用してユーザーを認証する方法を説明します。

    2。 MongoDBを使用したSpringセキュリティ認証

    JPAリポジトリを使用するのと同様に、MongoDBリポジトリを使用できます 。ただし、使用するには別の構成を設定する必要があります。

    2.1。 Mavenの依存関係

    このチュートリアルでは、EmbeddedMongoDBを使用します 。ただし、MongoDBインスタンスと Testcontainer 実稼働環境の有効なオプションである可能性があります。まず、 spring-boot-starter-data-mongodbを追加しましょう およびde.flapdoodle.embed.mongo 依存関係:

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>de.flapdoodle.embed</groupId>
        <artifactId>de.flapdoodle.embed.mongo</artifactId>
        <version>3.3.1</version>
    </dependency>

    2.2。構成

    依存関係を設定したら、構成を作成できます:

    @Configuration
    public class MongoConfig {
    
        private static final String CONNECTION_STRING = "mongodb://%s:%d";
        private static final String HOST = "localhost";
    
        @Bean
        public MongoTemplate mongoTemplate() throws Exception {
    
            int randomPort = SocketUtils.findAvailableTcpPort();
    
            ImmutableMongodConfig mongoDbConfig = MongodConfig.builder()
              .version(Version.Main.PRODUCTION)
              .net(new Net(HOST, randomPort, Network.localhostIsIPv6()))
              .build();
    
            MongodStarter starter = MongodStarter.getDefaultInstance();
            MongodExecutable mongodExecutable = starter.prepare(mongoDbConfig);
            mongodExecutable.start();
            return new MongoTemplate(MongoClients.create(String.format(CONNECTION_STRING, HOST, randomPort)), "mongo_auth");
        }
    }

    AuthenticationManagerも構成する必要があります たとえば、HTTP基本認証を使用します:

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        // ...
        public SecurityConfig(UserDetailsService userDetailsService) {
            this.userDetailsService = userDetailsService;
        }
    
        @Bean
        public AuthenticationManager customAuthenticationManager() throws Exception {
            return authenticationManager();
        }
    
        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Override
        protected void configure(@Autowired AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService)
              .passwordEncoder(bCryptPasswordEncoder());
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf()
              .disable()
              .authorizeRequests()
              .and()
              .httpBasic()
              .and()
              .authorizeRequests()
              .anyRequest()
              .permitAll()
              .and()
              .sessionManagement()
              .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        }
    }

    2.3。ユーザードメインとリポジトリ

    まず、認証用のロールを持つ単純なユーザーを定義しましょう。 UserDetailsを実装します プリンシパルのコモンズメソッドを再利用するためのインターフェイス オブジェクト:

    @Document
    public class User implements UserDetails {
        private @MongoId ObjectId id;
        private String username;
        private String password;
        private Set<UserRole> userRoles;
        // getters and setters
    }
    

    ユーザーができたので、簡単なリポジトリを定義しましょう:

    public interface UserRepository extends MongoRepository<User, String> {
    
        @Query("{username:'?0'}")
        User findUserByUsername(String username);
    }

    2.4。認証サービス

    最後に、 UserDetailServiceを実装しましょう。 ユーザーを取得して、認証されているかどうかを確認するため

    @Service
    public class MongoAuthUserDetailService implements UserDetailsService {
        // ...
        @Override
        public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
    
            com.baeldung.mongoauth.domain.User user = userRepository.findUserByUsername(userName);
    
            Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
    
            user.getAuthorities()
              .forEach(role -> {
                  grantedAuthorities.add(new SimpleGrantedAuthority(role.getRole()
                     .getName()));
              });
    
            return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
        }
    
    }

    2.5。認証のテスト

    アプリケーションをテストするために、簡単なコントローラーを定義しましょう。例として、特定のエンドポイントの認証と承認をテストするために2つの異なる役割を定義しました。

    @RestController
    public class ResourceController {
    
        @RolesAllowed("ROLE_ADMIN")
        @GetMapping("/admin")
        public String admin() {
            return "Hello Admin!";
        }
    
        @RolesAllowed({ "ROLE_ADMIN", "ROLE_USER" })
        @GetMapping("/user")
        public String user() {
            return "Hello User!";
        }
    
    }

    すべてをSpringBootTestでまとめて、認証が機能するかどうかを確認しましょう。ご覧のとおり、無効なクレデンシャルを提供している人やシステムに存在しない人には401コードが必要です

    class MongoAuthApplicationTest {
    
        // set up
    
        @Test
        void givenUserCredentials_whenInvokeUserAuthorizedEndPoint_thenReturn200() throws Exception {
            mvc.perform(get("/user").with(httpBasic(USER_NAME, PASSWORD)))
              .andExpect(status().isOk());
        }
    
        @Test
        void givenUserNotExists_whenInvokeEndPoint_thenReturn401() throws Exception {
            mvc.perform(get("/user").with(httpBasic("not_existing_user", "password")))
              .andExpect(status().isUnauthorized());
        }
    
        @Test
        void givenUserExistsAndWrongPassword_whenInvokeEndPoint_thenReturn401() throws Exception {
            mvc.perform(get("/user").with(httpBasic(USER_NAME, "wrong_password")))
              .andExpect(status().isUnauthorized());
        }
    
        @Test
        void givenUserCredentials_whenInvokeAdminAuthorizedEndPoint_thenReturn403() throws Exception {
            mvc.perform(get("/admin").with(httpBasic(USER_NAME, PASSWORD)))
              .andExpect(status().isForbidden());
        }
    
        @Test
        void givenAdminCredentials_whenInvokeAdminAuthorizedEndPoint_thenReturn200() throws Exception {
            mvc.perform(get("/admin").with(httpBasic(ADMIN_NAME, PASSWORD)))
              .andExpect(status().isOk());
    
            mvc.perform(get("/user").with(httpBasic(ADMIN_NAME, PASSWORD)))
              .andExpect(status().isOk());
        }
    }

    1. MongoDBの管理に関する考慮事項

    2. phpmongodbはコレクション内のn番目のエントリを検索します

    3. MongoDB $ dateFromParts

    4. モジュールソケットが見つかりませんlua