Spring Security OAuth2整合JWT
文章目录
- 1. Spring Security 与 OAuth2
- 2. Spring Security OAuth2的配置和使用
- ①:引入依赖
- ②:配置 spring security
- ③:配置授权服务器
- ④:配置redis、并生成 RedisTokenStore 的token存储方式
- 2. Spring Security OAuth2 整合 JWT
- ①:引入依赖
- ②:生成 JwtTokenStore 的token存储方式
- 如何对 token 进行增强?
1. Spring Security 与 OAuth2
Spring Security
是一个能够为基于Spring
的企业应用系统提供声明式的安全访问控制解决方案的安全框架,主要内容包括 认证(Authentication
) 和 授权(Authorization
)!
认证(Authentication)
- 用户认证就是判断一个用户的身份是否合法的过程,用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问,不合法则拒绝访问。
- 常见的用户身份认证方式有:用户名密码登录,二维码登录,手机短信登录,指纹认证等方式。
授权(Authorization)
- 授权是用户认证通过根据用户的权限来控制用户访问资源的过程,拥有资源的访问权限则正常访问,没有权限则拒绝访问。
Outh2的内容详情可以点此查看!
将OAuth2和Spring Security集成,就可以得到一套完整的安全解决方案Spring Security OAuth2
。本章我们将使用Spring Security OAuth2
构建一个授权服务器来验证用户身份以提供access_token,并使用这个access_token来从资源服务器请求数据。
2. Spring Security OAuth2的配置和使用
①:引入依赖
如果是spring boot
项目,需要引入
//spring整合security
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>//security整合outh2
<dependency><groupId>org.springframework.security.oauth</groupId><artifactId>spring-security-oauth2</artifactId><version>2.3.4.RELEASE</version>
</dependency>
如果是spring cloud
项目,需要引入
//只需引入这一个即可:此依赖整合了security、oauth2
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>// spring cloud
<dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR8</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>
②:配置 spring security
@Configuration
@EnableWebSecurity //这个可以不用写,磁层默认支持了
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}//自己的类实现了UserDetailsService,注入即可@Autowiredprivate UserService userService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 获取用户信息auth.userDetailsService(userService);}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin()//登录请求直接通过.permitAll()//所有请求过来.and().authorizeRequests()// oauth/** 开头的请求直接通过,因为要访问outh2授权服务器.antMatchers("/oauth/**").permitAll()//其他所有请求都要进行认证.anyRequest().authenticated()//登出请求直接通过.and().logout().permitAll()//解决跨域.and().csrf().disable();}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {// oauth2 密码模式需要拿到这个beanreturn super.authenticationManagerBean();}
}
用户信息类UserService
//用户信息可以使用使用一个类 实现UserDetailsService
@Service
public class UserService implements UserDetailsService {@Autowired@Lazyprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {String password = passwordEncoder.encode("123456");//可以去查数据库,这里直接newreturn new User("fox",password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));}
}
③:配置授权服务器
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig2 extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate AuthenticationManager authenticationManagerBean;@Autowiredprivate UserService userService;@Autowiredprivate TokenStore tokenStore;/*** 密码模式需要outh2授权服务器去校验账号、密码* 账号、密码在整合security时,放在security中了* 所以需要整合security的授权管理器authenticationManagerBean*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManagerBean) //使用密码模式需要配置.tokenStore(tokenStore) //指定token存储到redis,还有数据库、内存、jwt等存储方式!.reuseRefreshTokens(false) //refresh_token是否重复使用.userDetailsService(userService) //这一步包含账号、密码的检查!.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST); //支持GET,POST请求}@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {//允许表单认证security.allowFormAuthenticationForClients()// 配置校验token需要带入clientId 和clientSeret配置.checkTokenAccess("isAuthenticated()");}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {/***授权码模式*http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all*http://localhost:8080/oauth/authorize?response_type=code&client_id=client** implicit: 简化模式*http://localhost:8080/oauth/authorize?client_id=client&response_type=token&scope=all&redirect_uri=http://www.baidu.com** password模式* http://localhost:8080/oauth/token?username=fox&password=123456&grant_type=password&client_id=client&client_secret=123123&scope=all** 客户端模式* http://localhost:8080/oauth/token?grant_type=client_credentials&scope=all&client_id=client&client_secret=123123** 刷新令牌* http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123123&refresh_token=[refresh_token值]*/clients.inMemory()//配置client_id.withClient("client")//配置client-secret.secret(passwordEncoder.encode("123123"))//配置访问token的有效期.accessTokenValiditySeconds(3600)//配置刷新token的有效期.refreshTokenValiditySeconds(864000)//配置redirect_uri,用于授权成功后跳转.redirectUris("http://www.baidu.com")//配置申请的权限范围.scopes("all")/*** 配置grant_type,表示授权类型* authorization_code: 授权码模式* implicit: 简化模式* password: 密码模式* client_credentials: 客户端模式* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code","implicit","password","client_credentials","refresh_token");}
}
④:配置redis、并生成 RedisTokenStore 的token存储方式
spring:redis:host: 127.0.0.1database: 0
@Configuration
public class RedisConfig {@Autowiredprivate RedisConnectionFactory redisConnectionFactory;@Beanpublic TokenStore tokenStore(){return new RedisTokenStore(redisConnectionFactory);}
}
2. Spring Security OAuth2 整合 JWT
不懂JWT的可以点击查看此文章! Spring Security OAuth2 整合 JWT过程与第1节的步骤类似,都有如下几步
- ①:引入依赖,与第1节步骤不同,此处需要引入
jwt
依赖 - ②:配置
spring security
- ③:配置授权服务器
- ④:配置 token 存储方式,与第1节步骤不同,此处需要引入
JwtTokenStore
的token存储方式!
只不过第①步和第④步稍有不同罢了,此处只将不同点列出!
①:引入依赖
以spring cloud
项目为例,需要引入
// <!--JWT依赖-->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>// <!--security 整合 jwt-->
<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-jwt</artifactId><version>1.0.9.RELEASE</version>
</dependency>//只需引入这一个即可:此依赖整合了security、oauth2
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>// spring cloud
<dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR8</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>
②:生成 JwtTokenStore 的token存储方式
/*** 使用Jwt存储token的配置*/
@Configuration
public class JwtTokenStoreConfig {@Beanpublic TokenStore jwtTokenStore(){//传入一个 token转换器return new JwtTokenStore(jwtAccessTokenConverter());}//生成一个 token转换器@Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter(){JwtAccessTokenConverter accessTokenConverter = newJwtAccessTokenConverter();//配置JWT使用的秘钥、盐值123123accessTokenConverter.setSigningKey("123123");return accessTokenConverter;}// JwtTokenEnhancer :自定义增强器//把 token增强器 JwtTokenEnhancer 放入容器@Beanpublic JwtTokenEnhancer jwtTokenEnhancer() {return new JwtTokenEnhancer();}
}
这样就Spring Security OAuth2 就与 JWT 整合成功了,解密时就必须拿上文配置的盐值123123
来进行解密,否则解密失败!
//解密代码!
Jwts.parser().setSigningKey("123123".getBytes(StandardCharsets.UTF_8)).parseClaimsJws(token).getBody();
如何对 token 进行增强?
Outh2提供了一个接口TokenEnhancer
,可以对token进行增强,只需实现该接口即可
//token内容增强器
//注意需要注入容器
@Component
public class JwtTokenEnhancer implements TokenEnhancer {@Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken accessToken,OAuth2Authentication authentication) {Map<String, Object> info = new HashMap<>();//为原有的token的载荷增加一些内容//在对token进行解密时,就可以拿到这里添加的信息info.put("enhance", "enhance info");((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);return accessToken;}
}
然后把该增强器配置进outh2
的授权服务器即可!这样在解析token
时就可以解析到增强的内容!
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig3 extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate AuthenticationManager authenticationManagerBean;@Autowiredprivate UserService userService;@Autowired@Qualifier("jwtTokenStore")private TokenStore tokenStore;@Autowiredprivate JwtAccessTokenConverter jwtAccessTokenConverter;@Autowiredprivate JwtTokenEnhancer jwtTokenEnhancer;@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {//配置JWT的内容增强器,TokenEnhancer可以对token进行增强!TokenEnhancerChain enhancerChain = new TokenEnhancerChain();List<TokenEnhancer> delegates = new ArrayList<>();//添加token增强器delegates.add(jwtTokenEnhancer);//添加转换器delegates.add(jwtAccessTokenConverter);//把增强内容放入 增强链中enhancerChain.setTokenEnhancers(delegates);endpoints.authenticationManager(authenticationManagerBean) //使用密码模式需要配置.tokenStore(tokenStore) //配置存储令牌策略.accessTokenConverter(jwtAccessTokenConverter).tokenEnhancer(enhancerChain) //配置token增强链.reuseRefreshTokens(false) //refresh_token是否重复使用.userDetailsService(userService) //刷新令牌授权包含对用户信息的检查.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST); //支持GET,POST请求}@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {//允许表单认证security.allowFormAuthenticationForClients()// 获取密钥需要身份认证,使用单点登录时必须配置.tokenKeyAccess("isAuthenticated()");}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {/***授权码模式*http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://localhost:8081/login&scope=all*http://localhost:8080/oauth/authorize?response_type=code&client_id=client** password模式* http://localhost:8080/oauth/token?username=fox&password=123456&grant_type=password&client_id=client&client_secret=123123&scope=all** 客户端模式* http://localhost:8080/oauth/token?grant_type=client_credentials&scope=all&client_id=client&client_secret=123123** 刷新令牌* http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123123&refresh_token=[refresh_token值]*/clients.inMemory()//配置client_id.withClient("client")//配置client-secret.secret(passwordEncoder.encode("123123"))//配置访问token的有效期.accessTokenValiditySeconds(3600)//配置刷新token的有效期.refreshTokenValiditySeconds(864000)//配置redirect_uri,用于授权成功后跳转.redirectUris("http://localhost:8081/login","http://localhost:8082/login")//自动授权配置.autoApprove(true)//配置申请的权限范围.scopes("all")/*** 配置grant_type,表示授权类型* authorization_code: 授权码* password: 密码* client_credentials: 客户端* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code","password","refresh_token");}}
Spring Security OAuth2整合JWT相关推荐
- JWT实战 Spring Security Oauth2整合JWT 整合SSO单点登录
文章目录 一.JWT 1.1 什么是JWT 1.2 JWT组成 头部(header) 载荷(payload) 签名(signature) 如何应用 1.3 JJWT 快速开始 创建token toke ...
- 基于 Spring Security OAuth2和 JWT 构建保护微服务系统
我们希望自己的微服务能够在用户登录之后才可以访问,而单独给每个微服务单独做用户权限模块就显得很弱了,从复用角度来说是需要重构的,从功能角度来说,也是欠缺的.尤其是前后端完全分离之后,我们的用户信息不一 ...
- 《深入理解 Spring Cloud 与微服务构建》第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统
<深入理解 Spring Cloud 与微服务构建>第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统 文章目录 <深入理解 Spring Cl ...
- 使用Spring Security Oauth2 和 JWT保护微服务--Uaa授权服务器的编写
学习自深入理解微服务 采用Spring Security OAuth2 和 JWT的方式,Uaa服务只需要验证一次,返回JWT.返回的JWT包含了用户的所有信息,包括权限信息 从三个方面讲解: JWT ...
- 微信官方你真的懂OAuth2?Spring Security OAuth2整合企业微信扫码登录
❝ 企业微信扫码登录DEMO参见文末. 现在很多企业都接入了企业微信,作为私域社群工具,企业微信开放了很多API,可以打通很多自有的应用.既然是应用,那肯定需要做登录.正好企业微信提供了企业微信扫码授 ...
- 使用Spring Security Oauth2 和 JWT保护微服务--资源服务器的编写
编写hcnet-website的资源服务 依赖管理pom文件 hcnet-website工程的pom文件继承主maven的pom文件.在hcnet-website工程的pom文件中添加web功能的起步 ...
- Spring Security Oauth2 解析jwt
- 使用Spring Security OAuth2使用JWT生成token及自定义token携带的信息(十)
写在前面:各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟.多谢!如果我的博客对你有帮助,欢迎进行评论✏️✏️.点赞
- Spring Security OAuth2 改变jwt带默认authorities信息
上源码 Oauth2ServerConfig add处新增 @Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAcces ...
最新文章
- 一个完整的操作UI线程的例子,用到了多种方式
- Oracle 权限介绍及管理
- 的g极串一个电阻_负载电阻的原理及应用
- 互联网1分钟 |1120
- 人工智能、机器学习和深度学习的区别?
- 获取按钮点击次数_无限次数使用,不会吧?不会吧?
- java对象占用内存大小?
- Vue第二部分(2):组件的嵌套与通信
- 70. 爬楼梯(JavaScript)
- SAP License:第三方运输业务的外币付款处理
- DM9000有线网卡驱动编写
- html取消波浪线,PPT文字下划波浪线如何去掉?
- html + js实现马赛克画板
- FX5U 原点回归指令 DSZR
- 一文教你如何使用Mybatis Plugin 以及Druid Filer 改写SQL
- 【方向盘】启动命令和IDEA如何传递:VM参数、命令行参数、系统参数、环境变量参数、main方法参数
- 【小程序】之net::ERR_NAME_NOT_RESOLVED的问题
- openwrt劫持域名,openwrt使用DNS劫持实现访问域名访问web
- 什么是video codec? video codec在实际业务的应用。
- c语言指针p=*q,C语言中指针*p=*q与p=q有什么区别
热门文章
- 重庆师范大学第一届ACM选拔赛(公开赛)G-团日活动
- c语言程序设计电大作业,2018年最新电大C语言程序设计作业答案.doc
- 解决Oracle 本地可以连接,远程不能连接问题
- ssm数据库异常问题
- 审计导致select * 报ORA-01435: user does not exist
- Debian下PostgreSQL修改密码与配置详解
- duplicate database的时候,rman连接 auxiliary database的后状态不正确
- chrome和火狐获取资源
- 关于mysql单表支持的最大大小
- Apache2.4.1编译安装报错解决