好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Spring Security 单点登录简单示例详解

overview

最近在弄 单点登录 ,踩了不少坑,所以记录一下,做了个简单的例子。

目标:认证服务器认证后获取 token,客户端访问资源时带上 token 进行安全验证。

可以直接看 源码 。

关键依赖

?

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

<parent>

     <groupid>org.springframework.boot</groupid>

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

     <version> 2.1 . 2 .release</version>

     <relativepath/>

</parent>

 

<dependencies>

     <dependency>

       <groupid>org.springframework.boot</groupid>

       <artifactid>spring-boot-starter-security</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-test</artifactid>

       <scope>test</scope>

     </dependency>

     <dependency>

       <groupid>org.springframework.security</groupid>

       <artifactid>spring-security-test</artifactid>

       <scope>test</scope>

     </dependency>

     <dependency>

       <groupid>org.springframework.security.oauth.boot</groupid>

       <artifactid>spring-security-oauth2-autoconfigure</artifactid>

       <version> 2.1 . 2 .release</version>

     </dependency>

</dependencies>

认证服务器

认证服务器的关键代码有如下几个文件:

authserverapplication :

?

1

2

3

4

5

6

7

8

@springbootapplication

@enableresourceserver

public class authserverapplication {

   public static void main(string[] args) {

     springapplication.run(authserverapplication. class , args);

   }

 

}

authorizationserverconfiguration 认证配置:

?

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

@configuration

@enableauthorizationserver

class authorizationserverconfiguration extends authorizationserverconfigureradapter {

   @autowired

   authenticationmanager authenticationmanager;

 

   @autowired

   tokenstore tokenstore;

 

   @autowired

   bcryptpasswordencoder encoder;

 

   @override

   public void configure(clientdetailsserviceconfigurer clients) throws exception {

     //配置客户端

     clients

         .inmemory()

         .withclient( "client" )

         .secret(encoder.encode( "123456" )).resourceids( "hi" )

         .authorizedgranttypes( "password" , "refresh_token" )

         .scopes( "read" );

   }

 

   @override

   public void configure(authorizationserverendpointsconfigurer endpoints) throws exception {

     endpoints

         .tokenstore(tokenstore)

         .authenticationmanager(authenticationmanager);

   }

 

 

   @override

   public void configure(authorizationserversecurityconfigurer oauthserver) throws exception {

     //允许表单认证

     oauthserver

         .allowformauthenticationforclients()

         .checktokenaccess( "permitall()" )

         .tokenkeyaccess( "permitall()" );

   }

}

代码中配置了一个 client,id 是 client ,密码 123456 。 authorizedgranttypes 有 password 和 refresh_token 两种方式。

securityconfiguration 安全配置:

?

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

@configuration

@enablewebsecurity

public class securityconfiguration extends websecurityconfigureradapter {

   @bean

   public tokenstore tokenstore() {

     return new inmemorytokenstore();

   }

 

   @bean

   public bcryptpasswordencoder encoder() {

     return new bcryptpasswordencoder();

   }

 

   @override

   protected void configure(authenticationmanagerbuilder auth) throws exception {

     auth.inmemoryauthentication()

         .passwordencoder(encoder())

         .withuser( "user_1" ).password(encoder().encode( "123456" )).roles( "user" )

         .and()

         .withuser( "user_2" ).password(encoder().encode( "123456" )).roles( "admin" );

   }

 

   @override

   protected void configure(httpsecurity http) throws exception {

     // @formatter:off

     http.csrf().disable()

         .requestmatchers()

         .antmatchers( "/oauth/authorize" )

         .and()

         .authorizerequests()

         .anyrequest().authenticated()

         .and()

         .formlogin().permitall();

     // @formatter:on

   }

 

   @override

   @bean

   public authenticationmanager authenticationmanagerbean() throws exception {

     return super .authenticationmanagerbean();

   }

}

上面在内存中创建了两个用户,角色分别是 user 和 admin 。后续可考虑在数据库或者 redis 中存储相关信息。

authuser 配置获取用户信息的 controller:

?

1

2

3

4

5

6

7

8

@restcontroller

public class authuser {

     @getmapping ( "/oauth/user" )

     public principal user(principal principal) {

       return principal;

     }

 

}

application.yml 配置,主要就是配置个端口号:

?

1

2

3

4

5

6

7

8

---

spring:

  profiles:

   active: dev

  application:

   name: auth-server

server:

  port: 8101

客户端配置

客户端的配置比较简单,主要代码结构如下:

application.yml 配置:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

---

spring:

  profiles:

   active: dev

  application:

   name: client

 

server:

  port: 8102

security:

  oauth2:

   client:

    client-id: client

    client-secret: 123456

    access-token-uri: http: //localhost:8101/oauth/token

    user-authorization-uri: http: //localhost:8101/oauth/authorize

    scope: read

    use-current-uri: false

   resource:

    user-info-uri: http: //localhost:8101/oauth/user

这里主要是配置了认证服务器的相关地址以及客户端的 id 和 密码。 user-info-uri 配置的就是服务器端获取用户信息的接口。

hellocontroller 访问的资源,配置了 admin 的角色才可以访问:

?

1

2

3

4

5

6

7

8

@restcontroller

public class hellocontroller {

   @requestmapping ( "/hi" )

   @preauthorize ( "hasrole('admin')" )

   public responseentity<string> hi() {

     return responseentity.ok().body( "auth success!" );

   }

}

websecurityconfiguration 相关安全配置:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

@configuration

@enableoauth2sso

@enableglobalmethodsecurity (prepostenabled = true )

class websecurityconfiguration extends websecurityconfigureradapter {

 

   @override

   public void configure(httpsecurity http) throws exception {

 

     http

         .csrf().disable()

         // 基于token,所以不需要session

        .sessionmanagement().sessioncreationpolicy(sessioncreationpolicy.stateless)

         .and()

         .authorizerequests()

         .anyrequest().authenticated();

   }

 

 

}

其中 @enableglobalmethodsecurity(prepostenabled = true) 开启后,spring security 的 @preauthorize,@postauthorize 注解才可以使用。

@enableoauth2sso 配置了单点登录。

clientapplication :

?

1

2

3

4

5

6

7

8

@springbootapplication

@enableresourceserver

public class clientapplication {

   public static void main(string[] args) {

     springapplication.run(clientapplication. class , args);

   }

 

}

验证

启动项目后,我们使用 postman 来进行验证。

首先是获取 token:

选择 post 提交,地址为验证服务器的地址,参数中输入 username , password , grant_type 和 scope ,其中 grant_type 需要输入 password 。

然后在下面等 authorization 标签页中,选择 basic auth,然后输入 client 的 id 和 password。

?

1

2

3

4

5

6

7

{

   "access_token" : "02f501a9-c482-46d4-a455-bf79a0e0e728" ,

   "token_type" : "bearer" ,

   "refresh_token" : "0e62dddc-4f51-4cb5-81c3-5383fddbb81b" ,

   "expires_in" : 41741 ,

   "scope" : "read"

}

此时就可以获得 access_token 为: 02f501a9-c482-46d4-a455-bf79a0e0e728 。需要注意的是这里是用 user_2 获取的 token,即角色是 admin 。

然后我们再进行获取资源的验证:

使用 get 方法,参数中输入 access_token,值输入 02f501a9-c482-46d4-a455-bf79a0e0e728 。

点击提交后即可获取到结果。

如果我们不加上 token ,则会提示无权限。同样如果我们换上 user_1 获取的 token,因 user_1 的角色是 user ,此资源需要 admin 权限,则此处还是会获取失败。

简单的例子就到这,后续有时间再加上其它功能吧,谢谢~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

原文链接:https://segmentfault测试数据/a/1190000018323304

查看更多关于Spring Security 单点登录简单示例详解的详细内容...

  阅读:24次