好得很程序员自学网

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

Spring Security OAuth2实现使用JWT的示例代码

1、概括

在博客中,我们将讨论如何让spring security oauth2实现使用json web tokens。

2、maven 配置

首先,我们需要在我们的pom.xml中添加spring-security-jwt依赖项。

?

1

2

3

4

<dependency>

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

   <artifactid>spring-security-jwt</artifactid>

</dependency>

我们需要为authorization server和resource server添加spring-security-jwt依赖项。

3、授权服务器

接下来,我们将配置我们的授权服务器使用jwttokenstore - 如下所示

?

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

@configuration

@enableauthorizationserver

public class oauth2authorizationserverconfig extends authorizationserverconfigureradapter {

   @override

   public void configure(authorizationserverendpointsconfigurer endpoints) throws exception {

     endpoints.tokenstore(tokenstore())

          .accesstokenconverter(accesstokenconverter())

          .authenticationmanager(authenticationmanager);

   }

 

   @bean

   public tokenstore tokenstore() {

     return new jwttokenstore(accesstokenconverter());

   }

 

   @bean

   public jwtaccesstokenconverter accesstokenconverter() {

     jwtaccesstokenconverter converter = new jwtaccesstokenconverter();

     converter.setsigningkey( "123" );

     return converter;

   }

 

   @bean

   @primary

   public defaulttokenservices tokenservices() {

     defaulttokenservices defaulttokenservices = new defaulttokenservices();

     defaulttokenservices.settokenstore(tokenstore());

     defaulttokenservices.setsupportrefreshtoken( true );

     return defaulttokenservices;

   }

}

 请注意,在jwtaccesstokenconverter中使用了一个对称密钥来签署我们的令牌 - 这意味着我们需要为资源服务器使用同样的确切密钥。

4、资源服务器

现在,我们来看看我们的资源服务器配置 - 这与授权服务器的配置非常相似:

?

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

@configuration

@enableresourceserver

public class oauth2resourceserverconfig extends resourceserverconfigureradapter {

   @override

   public void configure(resourceserversecurityconfigurer config) {

     config.tokenservices(tokenservices());

   }

 

   @bean

   public tokenstore tokenstore() {

     return new jwttokenstore(accesstokenconverter());

   }

 

   @bean

   public jwtaccesstokenconverter accesstokenconverter() {

     jwtaccesstokenconverter converter = new jwtaccesstokenconverter();

     converter.setsigningkey( "123" );

     return converter;

   }

 

   @bean

   @primary

   public defaulttokenservices tokenservices() {

     defaulttokenservices defaulttokenservices = new defaulttokenservices();

     defaulttokenservices.settokenstore(tokenstore());

     return defaulttokenservices;

   }

}

 请记住,我们将这两个服务器定义为完全独立且可独立部署的服务器。这就是我们需要在新配置中再次声明一些相同的bean的原因。

5、令牌中的自定义声明

现在让我们设置一些基础设施,以便能够在访问令牌中添加一些自定义声明。框架提供的标准声明都很好,但大多数情况下我们需要在令牌中使用一些额外的信息来在客户端使用。 我们将定义一个tokenenhancer来定制我们的access token与这些额外的声明。 在下面的例子中,我们将添加一个额外的字段[组织]到我们的访问令牌 - 与此customtokenenhancer:

?

1

2

3

4

5

6

7

8

9

10

11

public class customtokenenhancer implements tokenenhancer {

   @override

   public oauth2accesstoken enhance(

    oauth2accesstoken accesstoken,

    oauth2authentication authentication) {

     map<string, object> additionalinfo = new hashmap<>();

     additionalinfo.put( "organization" , authentication.getname() + randomalphabetic( 4 ));

     ((defaultoauth2accesstoken) accesstoken).setadditionalinformation(additionalinfo);

     return accesstoken;

   }

}

然后,我们将把它连接到我们的授权服务器配置 - 如下所示:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@override

public void configure(authorizationserverendpointsconfigurer endpoints) throws exception {

   tokenenhancerchain tokenenhancerchain = new tokenenhancerchain();

   tokenenhancerchain.settokenenhancers(

    arrays.aslist(tokenenhancer(), accesstokenconverter()));

 

   endpoints.tokenstore(tokenstore())

        .tokenenhancer(tokenenhancerchain)

        .authenticationmanager(authenticationmanager);

}

 

@bean

public tokenenhancer tokenenhancer() {

   return new customtokenenhancer();

}

有了这个新的配置启动和运行 - 这是一个令牌令牌有效载荷看起来像:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

{

   "user_name" : "john" ,

   "scope" : [

     "foo" ,

     "read" ,

     "write"

   ],

   "organization" : "johniich" ,

   "exp" : 1458126622 ,

   "authorities" : [

     "role_user"

   ],

   "jti" : "e0ad1ef3-a8a5-4eef-998d-00b26bc2c53f" ,

   "client_id" : "fooclientidpassword"

}

5.1、在js客户端使用访问令牌

最后,我们要在angualrjs客户端应用程序中使用令牌信息。我们将使用angular-jwt库。 所以我们要做的就是在index.html中使用[组织]声明:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<p class = "navbar-text navbar-right" >{{organization}}</p>

 

<script type= "text/javascript"

  src= "https://cdn.rawgit.com/auth0/angular-jwt/master/dist/angular-jwt.js" >

</script>

 

<script>

var app = angular.module( 'myapp' , [ "ngresource" , "ngroute" , "ngcookies" , "angular-jwt" ]);

 

app.controller( 'mainctrl' , function($scope, $cookies, jwthelper,...) {

   $scope.organiztion = "" ;

 

   function getorganization(){

     var token = $cookies.get( "access_token" );

     var payload = jwthelper.decodetoken(token);

     $scope.organization = payload.organization;

   }

   ...

});

6、不对称的keypair

在我们以前的配置中,我们使用对称密钥来签署我们的令牌:

?

1

2

3

4

5

6

@bean

public jwtaccesstokenconverter accesstokenconverter() {

   jwtaccesstokenconverter converter = new jwtaccesstokenconverter();

   converter.setsigningkey( "123" );

   return converter;

}

我们还可以使用非对称密钥(公钥和私钥)来执行签名过程。

6.1、生成jks java keystore文件

我们首先使用命令行工具keytool生成密钥 - 更具体地说.jks文件:

?

1

2

3

4

5

keytool -genkeypair -alias mytest

           -keyalg rsa

           -keypass mypass

           -keystore mytest.jks

           -storepass mypass

该命令将生成一个名为mytest.jks的文件,其中包含我们的密钥 - 公钥和私钥。 还要确保keypass和storepass是一样的。

6.2、导出公钥

接下来,我们需要从生成的jks中导出我们的公钥,我们可以使用下面的命令来实现:

?

1

keytool -list -rfc --keystore mytest.jks | openssl x509 -inform pem -pubkey

示例回应如下所示:

?

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

-----begin public key-----

miibijanbgkqhkig9w0baqefaaocaq8amiibcgkcaqeagik2wt4x2etdl41c7vfp

osmquzmyoyteo2rsvemlf/hxieyvickr0sqzvkodhebcmigxqdz5prijtq3rhpy2

/5wjbcyq7yhgtlvspmy6sivxn7ndye7i5pxo/khk4nz+fa6p3l8+l90e/3qwf6j3

dkwnagjfry8absyxt1d5eliig1/geqzc0fzmnhhfrbtxwwxrlpudt0kfvf0qvmpr

xxclxt+tee1sewgeqeoll5vxrlqmzzcbe1rz9kqqm43+a9qn5icsrndftaesq3cr

lawjkl2kcwu1hwjqw+dzrsz1x4kexnmyzpdpbbgmu6mhdhpywi7skzt7mx4bdnuk

eqidaqab

-----end public key-----

-----begin certificate-----

miidczccafogawibagiegtziuzanbgkqhkig9w0baqsfada2mqswcqydvqqgewj1

czelmakga1uecbmcy2exczajbgnvbactamxhmq0wcwydvqqdewr0zxn0mb4xdte2

mdmxnta4mtazmfoxdte2mdyxmza4mtazmfownjelmakga1uebhmcdxmxczajbgnv

bagtamnhmqswcqydvqqhewjsytenmasga1ueaxmedgvzddccasiwdqyjkozihvcn

aqebbqadggepadccaqocggebaicctlremdhlq5enqu736trdkrmtmjsrxjtkbfxj

cxf4vyhml4ncq9ekm1zkhrxaqjihl0a8+aa4o06t0rz8tv+viqqmku8h4ey77ktm

urir1zezxwboyoav6pyh5oj8/hwuj9y/pi/dbp96sh+o9wylpwicruwpag0mf7dx

erc4ibtf4bkswth2zjyyx6wbccfl65ava09cn739efzj0ccqi10/rrhtbhlhhknj

iy+b10s6ps2xaxtuwfzeejun/mvuj+ynekzw30whrenwq5qfispdphflnr8caspn

wuumdv+jbfztmsz3twwxplojb3yacsco0imu+5l+aq51cnkcaweaaamhmb8whqyd

vr0obbyefogefubgquex9ujak34pyrskhk+wma0gcsqgsib3dqebcwuaa4ibaqb3

1elfneq45yo1cxnl0c1iqlknp2wxg89ahebkkuoa1zktoiznyjihw5myju/zscu0

ybobhtde5hdtsatma9sn5cpoaljwzpwv/zc6wyhawtfljzzc6d2rl3qyrsirxmsp

/j1vq9wkesqdshnegy7ggrgjn4a8ckechszqyzxulq7zah6goeud+vjb+bhep4an

hiyy1ouxd+hsdkeqqs+7em5u7ww6dz2q8mtfj5qaxjy75t0pprhwzmljuhuz+q2v

ffwejeaonb9w9mcpe1caie+oeejz0jq0el3/djsx3rlvqzn+lmhrjjevhfyeb3xf

llfcugha7hxn2xf3x1jw

-----end certificate-----

我们只取得我们的公钥,并将其复制到我们的资源服务器src / main / resources / public.txt中

?

1

2

3

4

5

6

7

8

9

-----begin public key-----

miibijanbgkqhkig9w0baqefaaocaq8amiibcgkcaqeagik2wt4x2etdl41c7vfp

osmquzmyoyteo2rsvemlf/hxieyvickr0sqzvkodhebcmigxqdz5prijtq3rhpy2

/5wjbcyq7yhgtlvspmy6sivxn7ndye7i5pxo/khk4nz+fa6p3l8+l90e/3qwf6j3

dkwnagjfry8absyxt1d5eliig1/geqzc0fzmnhhfrbtxwwxrlpudt0kfvf0qvmpr

xxclxt+tee1sewgeqeoll5vxrlqmzzcbe1rz9kqqm43+a9qn5icsrndftaesq3cr

lawjkl2kcwu1hwjqw+dzrsz1x4kexnmyzpdpbbgmu6mhdhpywi7skzt7mx4bdnuk

eqidaqab

-----end public key-----

6.3、maven 配置

接下来,我们不希望jms文件被maven过滤进程拾取 - 所以我们将确保将其排除在pom.xml中:

?

1

2

3

4

5

6

7

8

9

10

11

<build>

   <resources>

     <resource>

       <directory>src/main/resources</directory>

       <filtering> true </filtering>

       <excludes>

         <exclude>*.jks</exclude>

       </excludes>

     </resource>

   </resources>

</build>

如果我们使用spring boot,我们需要确保我们的jks文件通过spring boot maven插件添加到应用程序classpath - addresources:

?

1

2

3

4

5

6

7

8

9

10

11

<build>

   <plugins>

     <plugin>

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

       <artifactid>spring-boot-maven-plugin</artifactid>

       <configuration>

         <addresources> true </addresources>

       </configuration>

     </plugin>

   </plugins>

</build>

6.4、授权服务器

现在,我们将配置jwtaccesstokenconverter使用mytest.jks中的keypair,如下所示:

?

1

2

3

4

5

6

7

8

@bean

public jwtaccesstokenconverter accesstokenconverter() {

   jwtaccesstokenconverter converter = new jwtaccesstokenconverter();

   keystorekeyfactory keystorekeyfactory =

    new keystorekeyfactory( new classpathresource( "mytest.jks" ), "mypass" .tochararray());

   converter.setkeypair(keystorekeyfactory.getkeypair( "mytest" ));

   return converter;

}

6.5、资源服务器

最后,我们需要配置我们的资源服务器使用公钥 - 如下所示:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

@bean

public jwtaccesstokenconverter accesstokenconverter() {

   jwtaccesstokenconverter converter = new jwtaccesstokenconverter();

   resource resource = new classpathresource( "public.txt" );

   string publickey = null ;

   try {

     publickey = ioutils.tostring(resource.getinputstream());

   } catch ( final ioexception e) {

     throw new runtimeexception(e);

   }

   converter.setverifierkey(publickey);

   return converter;

}

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

原文链接:https://blog.csdn.net/chenjianandiyi/article/details/78604376

查看更多关于Spring Security OAuth2实现使用JWT的示例代码的详细内容...

  阅读:48次