Spring Boot學習筆記[5]-REST API使用Spring Security+OAuth2作權限控制

原文連接:http://lxgandlz.cn/404.htmlhtml

前面有一篇文章Spring+Spring Security+OAuth2實現REST API權限控制,講了Spring+Spring Security+OAuth2來實現REST API權限控制,出於快速實現的緣由,裏面的用戶信息和認證token都是保存在內存中。這樣並不符合實際項目場景。因此,這篇文章就是講述如何從數據庫中加載用戶信息,而且將認證token保存在redis中。
源碼地址:https://github.com/li5454yong/springboot-security-oauth2.git
首先來看項目結構

這個項目中用到了三張表,運行項目會自動在數據庫創建這三張表。前端

一、pom依賴

 

XHTMLjava

 

1mysql

2git

3github

4web

5redis

6spring

7sql

8

9

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

60

61

    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>1.4.4.RELEASE</version>

        <relativePath/> <!-- lookup parent from repository -->

    </parent>

 

    <repositories>

        <repository>

            <id>aliyunRepository</id>

            <name>myRepository</name>

            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>

            <snapshots>

                <enabled>false</enabled>

            </snapshots>

        </repository>

    </repositories>

 

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <java.version>1.7</java.version>

        <spring-security-oauth2.version>2.0.3.RELEASE</spring-security-oauth2.version>

    </properties>

 

    <dependencies>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-jdbc</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-redis</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-data-jpa</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-security</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.security.oauth</groupId>

            <artifactId>spring-security-oauth2</artifactId>

        </dependency>

        <dependency>

            <groupId>mysql</groupId>

            <artifactId>mysql-connector-java</artifactId>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

            <scope>test</scope>

        </dependency>

 

    </dependencies>

 

相對於Spring的集成,這裏去除了Spring的依賴,引入了Spring Boot的依賴、Spring data JPA依賴、redis依賴。

二、自定義UserDetailService

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

/**

* Created by lxg

* on 2017/2/20.

*/

public class MyUserDetailsService implements UserDetailsService {

 

    @Autowired

    private UserService userService;

 

    @Autowired

    private UserRoleService userRoleService;

    /**

     * 根據用戶名獲取登陸用戶信息

     * @param username

     * @return

     * @throws UsernameNotFoundException

     */

    @Override

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = userService.findByUsername(username);

        if(user == null){

             throw new UsernameNotFoundException("用戶名:"+ username + "不存在!");

        }

        Collection<SimpleGrantedAuthority> collection = new HashSet<SimpleGrantedAuthority>();

        Iterator<String> iterator =  userRoleService.findRoles(user.getId()).iterator();

        while (iterator.hasNext()){

            collection.add(new SimpleGrantedAuthority(iterator.next()));

        }

 

        return new org.springframework.security.core.userdetails.User(username,user.getPassword(),collection);

    }

}

 

這裏只須要實現UserDetailsService接口,實現loadUserByUsername方法,經過用戶名來獲取到用戶的信息。若是用戶不存在能夠拋出UsernameNotFoundException。而後經過userid來獲取用戶角色。由於一個用戶可能會擁有多個角色,因此這裏返回的是一個List。最後返回的是一個org.springframework.security.core.userdetails.User對象,裏面包含了用戶名、密碼、角色。也能夠根據本身須要去設置用戶是否被鎖定、是否可用等信息。

三、Security配置

 

Java

 

1

2

3

4

5

6

7

8

9

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

60

61

62

63

64

65

66

67

68

69

/**

* security配置

*

* @author lxg

*

* 2017年2月17日上午11:13:55

*/

@Configuration

@EnableWebSecurity

@EnableGlobalMethodSecurity(prePostEnabled = true)

public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {

 

@Autowired

private ClientDetailsService clientDetailsService;

 

@Autowired

private RedisConnectionFactory redisConnection;

 

@Bean

public MyUserDetailsService myUserDetailsService(){

return new MyUserDetailsService();

}

@Autowired

    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {

        auth

.userDetailsService(myUserDetailsService())

.passwordEncoder(new Md5PasswordEncoder());

    }

 

    

    @Override

    protected void configure(HttpSecurity http) throws Exception {

http

.anonymous().disable()

   .authorizeRequests()

   .antMatchers("/oauth/token").permitAll();

    }

 

    @Override

    @Bean

    public AuthenticationManager authenticationManagerBean() throws Exception {

        return super.authenticationManagerBean();

    }

 

 

@Bean

public TokenStore tokenStore() {

return new RedisTokenStore(redisConnection);

}

 

@Bean

@Autowired

public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){

TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();

handler.setTokenStore(tokenStore);

handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));

handler.setClientDetailsService(clientDetailsService);

return handler;

}

@Bean

@Autowired

public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {

TokenApprovalStore store = new TokenApprovalStore();

store.setTokenStore(tokenStore);

return store;

}

}

 

只要在這裏面實例化MyUserDetailService,而後經過AuthenticationManagerBuilderuserDetailsService方法,設置進去就OK了。passwordEncoder方法設置的是用戶密碼的加密方式,這裏設置的是MD5加密,因此用戶從前端登陸時傳過來的密碼,在使用Security驗證時會自動使用MD5加密。

四、redis配置

 

TeX

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

# Redis數據庫索引(默認爲0)

spring.redis.database=1

# Redis服務器地址

spring.redis.host=192.168.0.12

# Redis服務器鏈接端口

spring.redis.port=6379

# Redis服務器鏈接密碼(默認爲空)

spring.redis.password=

# 鏈接池最大鏈接數(使用負值表示沒有限制)

spring.redis.pool.max-active=8

# 鏈接池最大阻塞等待時間(使用負值表示沒有限制)

spring.redis.pool.max-wait=-1

# 鏈接池中的最大空閒鏈接

spring.redis.pool.max-idle=8

# 鏈接池中的最小空閒鏈接

spring.redis.pool.min-idle=0

# 鏈接超時時間(毫秒)

spring.redis.timeout=0

 

Spring Boot中集成Redis很是簡單,只須要引入spring-boot-starter-redis依賴包,而後配置上連接信息就好了,Spring Boot的約束優於配置比起Spring着實方便很多。不知道Spring如何集成Redis的這裏有一個集成的Demo,能夠拿去參考一下。https://github.com/li5454yong/spring-redis.git

五、RedisTokenStore配置

 

Java

 

1

2

3

4

5

6

7

@Autowired

private RedisConnectionFactory redisConnection;

 

@Bean

public TokenStore tokenStore() {

return new RedisTokenStore(redisConnection);

}

 

TokenStore默認有四種實現,咱們這裏使用的是RedisTokenStore,他的構造方法中須要一個redis連接工廠。咱們直接將Spring容器管理的redisConnectionFactory注入進來便可。

六、測試

這裏的測試和Spring集成的測試方法同樣,這裏就不在贅述,不明白的能夠參考上一篇文章。

七、踩坑

2017-09-09更新
一些朋友在使用demo時遇到幾個問題,發現有一些地方沒說清楚,這裏更新一下。

一、密碼加密問題

 

Java

 

1

2

3

4

5

6

    @Autowired

    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {

        auth

.userDetailsService(myUserDetailsService())

.passwordEncoder(new Md5PasswordEncoder());

    }

代碼中已經配置了密碼使用MD5加密,因此使用demo時,插入到數據庫的密碼要使用MD5加密同樣。
若是你想使用其餘的方式加密也是能夠的,spring security提供了一下幾種加密

二、測試接口訪問時提示沒有權限。
Spring Security默認的角色前綴是」ROLE_」,使用hasRole方法時已經默認加上了,所以咱們在數據庫裏面的用戶角色應該是「ROLE_user」,在user前面加上」ROLE_」前綴

轉載請註明:大道至簡 » Spring Boot學習筆記[5]-REST API使用Spring Security+OAuth2作權限控制

相關文章
相關標籤/搜索