В предыдущем посте мы настраивали весеннюю конфигурацию безопасности, предоставляя настраиваемые запросы для пользователя и получения полномочий из базы данных SQL.
В настоящее время многие современные приложения используют базы данных NoSQL. Безопасность Spring не поставляется с готовым решением для баз данных NoSQL.
В этих случаях нам необходимо предоставить решение путем реализации пользовательского UserDetailsService.
Мы будем использовать базу данных MongoDB для этого примера. Я буду использовать образ докера , однако настроить базу данных mongodb так же просто, загрузив ее с официального сайта .
Вот некоторые команды для начала работы с docker и mongodb (не стесняйтесь их игнорировать, если вы не используете docker)
01
02
03
04
05
06
07
08
09
10
|
#pull the mongo image docker pull mongo #create a mongo container docker run --name some-mongo -d mongo #get the docker container id docker ps #get the containers ip docker inspect -- format '{{ .NetworkSettings.IPAddress }}' $CID #connection using the ip retrieved mongo $mongodb_container_ip |
Затем мы напишем простой скрипт инициализации с именем createuser.js. Сценарий создает документ, содержащий информацию о пользователе, такую как имя пользователя, пароль и права доступа.
1
2
|
use springsecurity db. users .insert({ "name" : "John" , "surname" : "doe" , "email" : "[email protected]" , "password" : "cleartextpass" , "authorities" :[ "user" , "admin" ]}) |
Мы будем использовать Mongo Cli для его выполнения.
1
|
mongo 172.17.0.2:27017 < createuser.js |
Чтобы использовать Spring Security с mongodb, нам нужно получить информацию о пользователях из коллекции пользователей.
Первым шагом является добавление зависимостей mongodb в наш файл gradle, включая драйвер mongodb. Обратите внимание, что мы будем использовать профиль под названием «customuserdetails».
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
group 'com.gkatzioura' version '1.0-SNAPSHOT' buildscript { repositories { mavenCentral() } dependencies { classpath( "org.springframework.boot:spring-boot-gradle-plugin:1.4.0.RELEASE" ) } } apply plugin: 'java' apply plugin: 'idea' apply plugin: 'spring-boot' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile( "org.springframework.boot:spring-boot-starter-web" ) compile( "org.thymeleaf:thymeleaf-spring4" ) compile( "org.springframework.boot:spring-boot-starter-security" ) compile( "org.mongodb:mongo-java-driver:1.3" ) compile( "org.slf4j:slf4j-api:1.6.6" ) compile( "ch.qos.logback:logback-core:1.1.7" ) compile( "ch.qos.logback:logback-classic:1.1.7" ) testCompile "junit:junit:4.11" } bootRun { systemProperty "spring.profiles.active" , "customuserdetails" } |
Затем мы создадим компонент подключения mongodb.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package com.gkatzioura.spring.security.config; import com.mongodb.Mongo; import com.mongodb.MongoClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; /** * Created by gkatzioura on 9/27/16. */ @Configuration @Profile ( "customuserdetails" ) public class MongoConfiguration { @Bean public MongoClient createConnection() { //You should put your mongo ip here return new MongoClient( "172.17.0.2:27017" ); } } |
Затем мы создадим пользовательский объект сведений о пользователе.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
package com.gkatzioura.spring.security.model; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.UserDetails; import java.util.Collection; import java.util.List; /** * Created by gkatzioura on 9/27/16. */ public class MongoUserDetails implements UserDetails{ private String username; private String password; private List<GrantedAuthority> grantedAuthorities; public MongoUserDetails(String username,String password,String[] authorities) { this .username = username; this .password = password; this .grantedAuthorities = AuthorityUtils.createAuthorityList(authorities); } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return grantedAuthorities; } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true ; } @Override public boolean isAccountNonLocked() { return true ; } @Override public boolean isCredentialsNonExpired() { return true ; } @Override public boolean isEnabled() { return true ; } } |
Следующим шагом мы добавим пользовательский UserDetailsService, получающий информацию о пользователе через базу данных mongodb.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package com.gkatzioura.spring.security.service; import com.gkatzioura.spring.security.model.MongoUserDetails; import com.mongodb.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.Filters; import org.bson.Document; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.List; /** * Created by gkatzioura on 9/27/16. */ public class CustomerUserDetailsService implements UserDetailsService { @Autowired private MongoClient mongoClient; @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { MongoDatabase database = mongoClient.getDatabase( "springsecurity" ); MongoCollection<Document> collection = database.getCollection( "users" ); Document document = collection.find(Filters.eq( "email" ,email)).first(); if (document!= null ) { String name = document.getString( "name" ); String surname = document.getString( "surname" ); String password = document.getString( "password" ); List<String> authorities = (List<String>) document.get( "authorities" ); MongoUserDetails mongoUserDetails = new MongoUserDetails(email,password,authorities.toArray( new String[authorities.size()])); return mongoUserDetails; } return null ; } } |
Последний шаг — предоставить весеннюю конфигурацию безопасности, используя пользовательский UserDetailsService, который мы реализовали ранее.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package com.gkatzioura.spring.security.config; import com.gkatzioura.spring.security.service.CustomerUserDetailsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Profile; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; /** * Created by gkatzioura on 9/27/16. */ @EnableWebSecurity @Profile ( "customuserdetails" ) public class CustomUserDetailsSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public UserDetailsService mongoUserDetails() { return new CustomerUserDetailsService(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { UserDetailsService userDetailsService = mongoUserDetails(); auth.userDetailsService(userDetailsService); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers( "/public" ).permitAll() .anyRequest().authenticated() .and() .formLogin() .permitAll() .and() .logout() .permitAll(); } } |
Чтобы запустить проблему приложения
1
|
gradle bootRun |
Вы можете найти исходный код на GitHub
Ссылка: | Spring загружается с помощью Spring Security и NoSQL от нашего партнера по JCG Эммануила Гкатзиураса в блоге gkatzioura . |