51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Spring Security 使用 Mongodb 进行认证

  1. Overview {#1-overview}

Spring Security 提供了不同的身份认证系统,例如通过数据库和 UserDetailService

有时可能不想使用 JPA 持久层,而是想使用 MongoDB Repository。本文将带你了解如何使用 Spring Security 和 MongoDB 对用户进行认证。

2、Spring Security 使用 MongoDB 进行认证 {#2spring-security-使用-mongodb-进行认证}

MongoDB Repository 与 JPA Repository 类似不过,我们需要设置不同的配置。

2.1、Maven 依赖 {#21maven-依赖}

本文使用嵌入式 MongoDB。首先,添加 spring-boot-starter-data-mongodbde.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、配置 {#22配置}

创建配置类:

@Configuration
public class MongoConfig {
private static final String CONNECTION_STRING = &quot;mongodb://%s:%d&quot;;
private static final String HOST = &quot;localhost&quot;;

@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)), &amp;quot;mongo_auth&amp;quot;);

}

}

配置 AuthenticationManager,例如,使用 HTTP Basic Authentication:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig {
//...
public SecurityConfig(UserDetailsService userDetailsService) {
    this.userDetailsService = userDetailsService;
}

@Bean public AuthenticationManager customAuthenticationManager(HttpSecurity http) throws Exception { AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject (AuthenticationManagerBuilder.class); authenticationManagerBuilder.userDetailsService(userDetailsService) .passwordEncoder(bCryptPasswordEncoder()); return authenticationManagerBuilder.build(); }

@Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); }

@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf() .disable() .authorizeRequests() .and() .httpBasic() .and() .authorizeRequests() .anyRequest() .permitAll() .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); return http.build(); }

}

2.3、User Domain 和 Repository {#23user-domain-和-repository}

首先,为身份认证(Authentication)定义一个简单的带角色的 User,并且实现 UserDetails 接口,以继承 Principal 对象的常用方法:

@Document
public class User implements UserDetails {
    private @MongoId ObjectId id;
    private String username;
    private String password;
    private Set<UserRole> userRoles;
    // get / set 方法
}

然后,定义一个 Repository:

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

}

2.4、Authentication Service {#24authentication-service}

最后,实现 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&amp;lt;GrantedAuthority&amp;gt; grantedAuthorities = new HashSet&amp;lt;&amp;gt;();

user.getAuthorities()
  .forEach(role -&amp;gt; {
      grantedAuthorities.add(new SimpleGrantedAuthority(role.getRole()
         .getName()));
  });

return new User(user.getUsername(), user.getPassword(), grantedAuthorities);

}

}

2.5、测试认证 {#25测试认证}

定义一个简单的 Controller 用于测试。

例如:定义两个不同的角色,以测试指定端点的身份认证和授权:

@RestController
public class ResourceController {
@RolesAllowed(&quot;ROLE_ADMIN&quot;)
@GetMapping(&quot;/admin&quot;)
public String admin() {
    return &quot;Hello Admin!&quot;;
}

@RolesAllowed({ &quot;ROLE_ADMIN&quot;, &quot;ROLE_USER&quot; }) @GetMapping(&quot;/user&quot;) public String user() { return &quot;Hello User!&quot;; }

}

将所有内容封装在一个 Spring Boot 测试中,测试身份认证是否有效。

如下,对于提供无效凭证或在系统中不存在的用户,测试期望返回401状态码。

class MongoAuthApplicationTest {
// 设置

@Test void givenUserCredentials_whenInvokeUserAuthorizedEndPoint_thenReturn200() throws Exception { mvc.perform(get(&quot;/user&quot;).with(httpBasic(USER_NAME, PASSWORD))) .andExpect(status().isOk()); }

@Test void givenUserNotExists_whenInvokeEndPoint_thenReturn401() throws Exception { mvc.perform(get(&quot;/user&quot;).with(httpBasic(&quot;not_existing_user&quot;, &quot;password&quot;))) .andExpect(status().isUnauthorized()); }

@Test void givenUserExistsAndWrongPassword_whenInvokeEndPoint_thenReturn401() throws Exception { mvc.perform(get(&quot;/user&quot;).with(httpBasic(USER_NAME, &quot;wrong_password&quot;))) .andExpect(status().isUnauthorized()); }

@Test void givenUserCredentials_whenInvokeAdminAuthorizedEndPoint_thenReturn403() throws Exception { mvc.perform(get(&quot;/admin&quot;).with(httpBasic(USER_NAME, PASSWORD))) .andExpect(status().isForbidden()); }

@Test void givenAdminCredentials_whenInvokeAdminAuthorizedEndPoint_thenReturn200() throws Exception { mvc.perform(get(&quot;/admin&quot;).with(httpBasic(ADMIN_NAME, PASSWORD))) .andExpect(status().isOk());

mvc.perform(get(&amp;quot;/user&amp;quot;).with(httpBasic(ADMIN_NAME, PASSWORD)))
  .andExpect(status().isOk());

}

}

3、总结 {#3总结}

本文结介绍了 Spring Security 如何使用 MongoDB 进行用户的身份认证。


参考:https://www.baeldung.com/spring-security-authentication-mongodb

赞(3)
未经允许不得转载:工具盒子 » Spring Security 使用 Mongodb 进行认证