Статьи

Загрузка Spring с Spring Security и NoSQL

В предыдущем посте мы настраивали весеннюю конфигурацию безопасности, предоставляя настраиваемые запросы для пользователя и получения полномочий из базы данных 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":"john@doe.com","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