Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器
程序员文章站
2023-11-22 23:50:22
概要 之前的两篇文章,讲述了Spring Security 结合 OAuth2 、JWT 的使用,这一节要求对 OAuth2、JWT 有了解,若不清楚,先移步到下面两篇提前了解下。 "Spring Boot Security 整合 OAuth2 设计安全API接口服务" "Spring Boot S ......
概要
之前的两篇文章,讲述了spring security 结合 oauth2 、jwt 的使用,这一节要求对 oauth2、jwt 有了解,若不清楚,先移步到下面两篇提前了解下。
spring boot security 整合 oauth2 设计安全api接口服务
spring boot security 整合 jwt 实现 无状态的分布式api接口
这一篇我们来实现 支持 jwt令牌 的授权服务器。
优点
使用 oauth2 是向认证服务器申请令牌,客户端拿这令牌访问资源服务服务器,资源服务器校验了令牌无误后,如果资源的访问用到用户的相关信息,那么资源服务器还需要根据令牌关联查询用户的信息。
使用 jwt 是客户端通过用户名、密码 请求服务器获取 jwt,服务器判断用户名和密码无误之后,可以将用户信息和权限信息经过加密成 jwt 的形式返回给客户端。在之后的请求中,客户端携带 jwt 请求需要访问的资源,如果资源的访问用到用户的相关信息,那么就直接从jwt中获取到。
所以,如果我们在使用 oauth2 时结合jwt ,就能节省集中式令牌校验开销,实现无状态授权认证。
快速上手
项目说明
工程名 | 端口 | 作用 |
---|---|---|
jwt-authserver | 8080 | 授权服务器 |
jwt-resourceserver | 8081 | 资源服务器 |
授权服务器
pom.xml
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-oauth2-resource-server</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-security</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-oauth2-client</artifactid> </dependency> <dependency> <groupid>org.springframework.security.oauth.boot</groupid> <artifactid>spring-security-oauth2-autoconfigure</artifactid> <version>2.1.3.release</version> </dependency> <dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-jwt</artifactid> <version>1.0.10.release</version> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency>
websecurityconfig
@configuration public class websecurityconfig extends websecurityconfigureradapter { @override protected void configure(httpsecurity http) throws exception { http. authorizerequests().antmatchers("/**").permitall(); } @autowired public void configureglobal(authenticationmanagerbuilder auth) throws exception { auth .inmemoryauthentication() .withuser("user").password("123456").roles("user"); } @bean @override public authenticationmanager authenticationmanagerbean() throws exception { return super.authenticationmanagerbean(); } @bean public passwordencoder passwordencoder() { return new passwordencoder() { @override public string encode(charsequence charsequence) { return charsequence.tostring(); } @override public boolean matches(charsequence charsequence, string s) { return objects.equals(charsequence.tostring(),s); } }; } }
为了方便,使用内存模式,在内存中创建一个用户 user 密码 123456。
oauth2authorizationserver
/** * 授权服务器 */ @configuration @enableauthorizationserver public class oauth2authorizationserver extends authorizationserverconfigureradapter { /** * 注入authenticationmanager ,密码模式用到 */ @autowired private authenticationmanager authenticationmanager; /** * 对jwt签名时,增加一个密钥 * jwtaccesstokenconverter:对jwt来进行编码以及解码的类 */ @bean public jwtaccesstokenconverter accesstokenconverter() { jwtaccesstokenconverter converter = new jwtaccesstokenconverter(); converter.setsigningkey("test-secret"); return converter; } /** * 设置token 由jwt产生,不使用默认的透明令牌 */ @bean public jwttokenstore jwttokenstore() { return new jwttokenstore(accesstokenconverter()); } @override public void configure(authorizationserverendpointsconfigurer endpoints) throws exception { endpoints .authenticationmanager(authenticationmanager) .tokenstore(jwttokenstore()) .accesstokenconverter(accesstokenconverter()); } @override public void configure(clientdetailsserviceconfigurer clients) throws exception { clients.inmemory() .withclient("clientapp") .secret("123") .scopes("read") //设置支持[密码模式、授权码模式、token刷新] .authorizedgranttypes( "password", "authorization_code", "refresh_token"); } }
资源服务器
pom.xml
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-security</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-oauth2-resource-server</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-oauth2-client</artifactid> </dependency> <dependency> <groupid>org.springframework.security.oauth.boot</groupid> <artifactid>spring-security-oauth2-autoconfigure</artifactid> <version>2.1.3.release</version> </dependency> <dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-jwt</artifactid> <version>1.0.10.release</version> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency>
hellocontroller
@restcontroller("/api") public class hellocontroller { @postmapping("/api/hi") public string say(string name) { return "hi , " + name; } }
oauth2resourceserver
/** * 资源服务器 */ @configuration @enableresourceserver public class oauth2resourceserver extends resourceserverconfigureradapter { @override public void configure(httpsecurity http) throws exception { http .authorizerequests() .anyrequest().authenticated().and() .requestmatchers().antmatchers("/api/**"); } }
application.yml
server: port: 8081 security: oauth2: resource: jwt: key-value: test-secret
参数说明:
- security.oauth2.resource.jwt.key-value:设置签名key 保持和授权服务器一致。
- security.oauth2.resource.jwt:项目启动过程中,检查到配置文件中有
security.oauth2.resource.jwt 的配置,就会生成 jwttokenstore 的 bean,对令牌的校验就会使用 jwttokenstore 。
验证
请求令牌
curl -x post --user 'clientapp:123' -d 'grant_type=password&username=user&password=123456' http://localhost:8080/oauth/token
返回jwt令牌
{ "access_token": "eyjhbgcioijiuzi1niisinr5cci6ikpxvcj9.eyjlehaioje1ntq0mzexmdgsinvzzxjfbmftzsi6invzzxiilcjhdxrob3jpdgllcyi6wyjst0xfx1vtrviixswianrpijoiogm0ywmyotytmdqwys00y2uzltg5mtatmwjmnjzkytqwotk3iiwiy2xpzw50x2lkijoiy2xpzw50yxbwiiwic2nvcguiolsicmvhzcjdfq.yaasrn0iftmlr6khz9uxnnephhn8zhzwlqrcucpumsu", "token_type": "bearer", "refresh_token": "eyjhbgcioijiuzi1niisinr5cci6ikpxvcj9.eyj1c2vyx25hbwuioij1c2vyiiwic2nvcguiolsicmvhzcjdlcjhdgkioii4yzrhyzi5ni0wndbhltrjztmtodkxmc0xymy2nmrhnda5otcilcjlehaioje1nty5nzk5mdgsimf1dghvcml0awvzijpbiljptevfvvnfuijdlcjqdgkioii0zja5m2zjys04nmm0ltqxzwutodcxzs1kzty2zjfhoti0ntailcjjbgllbnrfawqioijjbgllbnrhchaifq.vvae2lcqggbv8pxuqu6rkpx65bl7zl9dfcoibiqblf4", "expires_in": 43199, "scope": "read", "jti": "8c4ac296-040a-4ce3-8910-1bf66da40997" }
携带jwt令牌请求资源
curl -x post -h "authorization: bearer eyjhbgcioijiuzi1niisinr5cci6ikpxvcj9.eyjlehaioje1ntq0mzexmdgsinvzzxjfbmftzsi6invzzxiilcjhdxrob3jpdgllcyi6wyjst0xfx1vtrviixswianrpijoiogm0ywmyotytmdqwys00y2uzltg5mtatmwjmnjzkytqwotk3iiwiy2xpzw50x2lkijoiy2xpzw50yxbwiiwic2nvcguiolsicmvhzcjdfq.yaasrn0iftmlr6khz9uxnnephhn8zhzwlqrcucpumsu" -d 'name=zhangsan' http://localhost:8081/api/hi
返回
hi , zhangsan
源码
https://github.com/gf-huanchupk/springbootlearning/tree/master/springboot-security-oauth2-jwt
欢迎扫码或微信搜索公众号《程序员果果》关注我,关注有惊喜~