文章目录

  • 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相关推荐

  1. JWT实战 Spring Security Oauth2整合JWT 整合SSO单点登录

    文章目录 一.JWT 1.1 什么是JWT 1.2 JWT组成 头部(header) 载荷(payload) 签名(signature) 如何应用 1.3 JJWT 快速开始 创建token toke ...

  2. 基于 Spring Security OAuth2和 JWT 构建保护微服务系统

    我们希望自己的微服务能够在用户登录之后才可以访问,而单独给每个微服务单独做用户权限模块就显得很弱了,从复用角度来说是需要重构的,从功能角度来说,也是欠缺的.尤其是前后端完全分离之后,我们的用户信息不一 ...

  3. 《深入理解 Spring Cloud 与微服务构建》第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统

    <深入理解 Spring Cloud 与微服务构建>第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统 文章目录 <深入理解 Spring Cl ...

  4. 使用Spring Security Oauth2 和 JWT保护微服务--Uaa授权服务器的编写

    学习自深入理解微服务 采用Spring Security OAuth2 和 JWT的方式,Uaa服务只需要验证一次,返回JWT.返回的JWT包含了用户的所有信息,包括权限信息 从三个方面讲解: JWT ...

  5. 微信官方你真的懂OAuth2?Spring Security OAuth2整合企业微信扫码登录

    ❝ 企业微信扫码登录DEMO参见文末. 现在很多企业都接入了企业微信,作为私域社群工具,企业微信开放了很多API,可以打通很多自有的应用.既然是应用,那肯定需要做登录.正好企业微信提供了企业微信扫码授 ...

  6. 使用Spring Security Oauth2 和 JWT保护微服务--资源服务器的编写

    编写hcnet-website的资源服务 依赖管理pom文件 hcnet-website工程的pom文件继承主maven的pom文件.在hcnet-website工程的pom文件中添加web功能的起步 ...

  7. Spring Security Oauth2 解析jwt

  8. 使用Spring Security OAuth2使用JWT生成token及自定义token携带的信息(十)

    写在前面:各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟.多谢!如果我的博客对你有帮助,欢迎进行评论✏️✏️.点赞

  9. Spring Security OAuth2 改变jwt带默认authorities信息

    上源码 Oauth2ServerConfig   add处新增 @Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAcces ...

最新文章

  1. 一个完整的操作UI线程的例子,用到了多种方式
  2. Oracle 权限介绍及管理
  3. 的g极串一个电阻_负载电阻的原理及应用
  4. 互联网1分钟 |1120
  5. 人工智能、机器学习和深度学习的区别?
  6. 获取按钮点击次数_无限次数使用,不会吧?不会吧?
  7. java对象占用内存大小?
  8. Vue第二部分(2):组件的嵌套与通信
  9. 70. 爬楼梯(JavaScript)
  10. SAP License:第三方运输业务的外币付款处理
  11. DM9000有线网卡驱动编写
  12. html取消波浪线,PPT文字下划波浪线如何去掉?
  13. html + js实现马赛克画板
  14. FX5U 原点回归指令 DSZR
  15. 一文教你如何使用Mybatis Plugin 以及Druid Filer 改写SQL
  16. 【方向盘】启动命令和IDEA如何传递:VM参数、命令行参数、系统参数、环境变量参数、main方法参数
  17. 【小程序】之net::ERR_NAME_NOT_RESOLVED的问题
  18. openwrt劫持域名,openwrt使用DNS劫持实现访问域名访问web
  19. 什么是video codec? video codec在实际业务的应用。
  20. c语言指针p=*q,C语言中指针*p=*q与p=q有什么区别

热门文章

  1. 重庆师范大学第一届ACM选拔赛(公开赛)G-团日活动
  2. c语言程序设计电大作业,2018年最新电大C语言程序设计作业答案.doc
  3. 解决Oracle 本地可以连接,远程不能连接问题
  4. ssm数据库异常问题
  5. 审计导致select * 报ORA-01435: user does not exist
  6. Debian下PostgreSQL修改密码与配置详解
  7. duplicate database的时候,rman连接 auxiliary database的后状态不正确
  8. chrome和火狐获取资源
  9. 关于mysql单表支持的最大大小
  10. Apache2.4.1编译安装报错解决