「Spring Boot 集成应用」 OAUTH2统一认证JWT+Redis+增强TOKEN方式
mhr18 2024-12-03 11:42 17 浏览 0 评论
1. 工程搭建
1、创建工程spring-boot-security-oauth2
2、启动类
com.mirson.spring.boot.security.oauth.startup.SecurityOauthApplication
@SpringBootApplication
@ComponentScan(basePackages = {"com.mirson"})
@EnableCaching
public class SecurityOauthApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityOauthApplication.class, args);
}
}
指定扫描路径, 开启缓存注解。
3、MAVEN依赖
POM.XML
<dependencies>
<!-- Spring Boot Security 安全依赖组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Spring Boot Oauth2 认证组件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!-- Spring Boot Web 依赖组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot 自动化缓存依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--Spring Boot Data Redis 缓存依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Apache Commons 工具依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
这里的依赖采用spring-cloud的OAUTH2封装来实现的自动化配置, 与spring-boot-starter-oauth2依赖实质是一样, 都是基于Spring-Security封装, 属性配置基本一致, 如果要加入Spring Cloud, 可以直接集成使用。
2. 创建用户对象
定义两个用户对象, 一个是OAUTH的用户认证对象, 一个是我们接口测试的用户对象。
2.1、OAUTH用户认证对象
com.mirson.spring.boot.security.oauth.po.OAuthUser
@Data
public class OAuthUser extends User {
/**
* 用户ID标识
*/
private Integer id;
/**
* 创建日期
*/
private Date createTime;
public OAuthUser(String account, String password){
super(account, password, true, true, true, true, Collections.EMPTY_SET);
this.id = RandomUtils.nextInt(0, 100);
this.createTime = new Date();
}
}
2.2、接口测试用户对象
com.mirson.spring.boot.security.oauth.po.User
@Data
public class User {
/**
* ID
*/
private Integer id;
/**
* 用户名称
*/
private String name;
/**
* 年龄
*/
private String age;
/**
* 省份
*/
private String province;
/**
* 创建时间
*/
private Date createDate;
}
2.3、提供资源接口
定义一个获取用户信息的接口, 受资源权限保护。
com.mirson.spring.boot.security.oauth.controller.UserController
@RestController
@RequestMapping("/user")
@Log4j2
public class UserController {
@RequestMapping("/getUserInfo")
@ResponseBody
public User getUserInfo() {
User user = new User();
user.setId(0);
user.setAge("21");
user.setName("user1");
user.setCreateDate(new Date());
return user;
}
}
4. OAUTH2集成与权限配置
4.1、工程配置
application.yml
# 服务端口
server:
port: 22619
# 服务名称
spring:
application:
name: security-oauth2
这里我们便于测试, 我们将认证服务和资源服务放置一起,以上配置即可, 不需加任何其他配置。
如果资源服务是独立的, 工程配置需要加入以下信息:
## spring security 配置
security:
oauth2:
resource:
jwt:
# JWT 密钥信息
key-value: sign_secret
# TOKEN验证接口地址
token-info-uri: http://127.0.0.1:21619/oauth/check_token
client:
# 客户端模式配置
client-id: demo
client-secret: 123456
scope: server
access-token-uri: http://127.0.0.1:21619/oauth/token
user-authorization-uri: http://127.0.0.1:21619/oauth/authorize
4.2、 认证服务配置
新建com.mirson.spring.boot.security.oauth.config.AuthorizationServerConfig配置类, 加入以下配置:
Redis配置:
/**
* Redis 缓存配置
* @return
*/
@Bean
public RedisTemplate<String, Object> stockRedisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
设置redis的key, value 序列化方式。
采用Redis存储TOKEN信息
/**
* TokenStore实现方式, 采用Redis缓存
* @return
*/
@Bean
public TokenStore redisTokenStore() {
RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
tokenStore.setPrefix(OAUTH_PREFIX_KEY);
tokenStore.setAuthenticationKeyGenerator(new DefaultAuthenticationKeyGenerator() {
@Override
public String extractKey(OAuth2Authentication authentication) {
return super.extractKey(authentication);
}
});
return tokenStore;
}
统一Redis的Key前缀, 便于维护。
结合Token增强技术
/**
* token增强处理, 支持扩展信息
* @return TokenEnhancer
*/
@Bean
public TokenEnhancer tokenEnhancer() {
return (accessToken, authentication) -> {
try {
if (OAUTH_CLIENT_CREDENTIALS
.equals(authentication.getOAuth2Request().getGrantType())) {
return accessToken;
}
final Map<String, Object> additionalInfo = new HashMap<>(16);
OAuthUser authUser = (OAuthUser) authentication.getUserAuthentication().getPrincipal();
if (null != authUser) {
// 放入扩展信息
additionalInfo.put("oauth_user_id", authUser.getId());
additionalInfo.put("oauth_user_date", authUser.getCreateTime());
additionalInfo.put("active", true);
}
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
}catch(Exception e) {
log.error(e.getMessage(), e);
}
return accessToken;
};
}
TOKEN增强可以放置额外信息,扩展性强, 更为灵活, 这些信息不会加入JWT中。
JWT TOKEN配置:
/**
* JWT TOKEN配置,采用签名密钥
*/
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(OAUTH_SIGN_KEY);
return converter;
}
JWT可以支持密钥签名, 还可以通过证书签名方式, 安全性比较高。
采用内存模式对客户端进行验证:
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.inMemory()
.withClient("demo")
.secret("4QrcOUm6Wau+VuBX8g+IPg==")
.authorizedGrantTypes("password", "authorization_code");
}
原始密码为123456, 我们采用了密码编码器, 这里的密码要设置为密文。
认证服务配置:
/**
* 认证服务配置
* @param endpoints
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
// 自定义token生成方式
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
endpoints
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
.tokenStore(redisTokenStore())
.tokenEnhancer(tokenEnhancerChain)
.userDetailsService(authCustomUserDetailService)
.authenticationManager(authenticationManager)
.reuseRefreshTokens(false);
}
采用Token链, 申请TOKEN的时候, 不仅返回JWT信息, 还返回TOKEN 增强设置的信息。
4.3、自定义密码编码器
com.mirson.spring.boot.security.oauth.config.AuthPasswordEncoder
/**
* 自定义密码加密方式
*/
@Component
@Log4j2
public class AuthPasswordEncoder implements PasswordEncoder {
/**
* 编码处理
* @param rawPassword
* @return
*/
@Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
/**
* 密码校验判断
* @param rawPassword
* @param encodedPassword
* @return
*/
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if(rawPassword != null && rawPassword.length() > 0){
try {
// 这里通过MD5及B64加密
String password = EncryptUtil.encryptSigned(rawPassword.toString());
boolean isMatch= encodedPassword.equals(password);
if(!isMatch) {
log.warn(" password not match!");
}
return encodedPassword.equals(password);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
return false;
}
}
可以自定义编码, 比如BASE64等, 自定义校验逻辑,能够灵活处理。
4.4、认证服务WEB配置
com.mirson.spring.boot.security.oauth.config.WebSecurityConfiguration
/**
* 认证相关配置
*/
@Primary
@Order(90)
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService authCustomClientDetailService;
@Autowired
private AuthPasswordEncoder authPasswordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/user/getUserInfo").authenticated()
.anyRequest().permitAll()
.and()
.csrf()
.disable() // 禁用csrf保护(防止伪造攻击)
.httpBasic().disable(); // 禁用弹出式认证框
}
@Bean
@Override
@SneakyThrows
public AuthenticationManager authenticationManagerBean() {
return super.authenticationManagerBean();
}
@Autowired
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(authCustomClientDetailService).passwordEncoder(authPasswordEncoder);
}
}
主要看configure方法配置, 设置哪些需要鉴权的接口地址, 禁用csrf保护, 防止无法请求的情况, 禁用弹出式认证框, 防止调用资源接口时出现401错误。
4.5、自定义用户服务接口
com.mirson.spring.boot.security.oauth.config.AuthCustomUserDetailService
@Service("authCustomUserDetailService")
public class AuthCustomUserDetailService implements UserDetailsService {
@Autowired
private CacheManager cacheManager;
@Override
public UserDetails loadUserByUsername(String userNo) throws UsernameNotFoundException {
// 查询缓存
Cache cache = cacheManager.getCache(AuthorizationServerConfig.OAUTH_KEY_USER_DETAILS);
if (cache != null && cache.get(userNo) != null) {
return (UserDetails) cache.get(userNo).get();
}
// 封装成OAUTH鉴权的用户对象
UserDetails userDetails = new OAuthUser("admin", "AZICOnu9cyUFFvBp3xi1AA==");
// 将用户信息放入缓存
cache.put(userNo, userDetails);
return userDetails;
}
}
这里加入了缓存处理, 实际项目当中, 也推荐使用缓存, 提升处理性能。
如果缓存没有用户, 会构造一个新的用户放入缓存, 密码要采用密文。
4.6、资源服务配置
如果有提供受保护的资源服务, 必须要做具体的配置。
新建com.mirson.spring.boot.security.oauth.config.ResourceServerConfiguration
/**
* 自定义资源服务器配置
*/
@EnableResourceServer
@Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/user/getUserInfo").authorizeRequests().anyRequest().authenticated();
}
}
设置了一个受保护的资源接口/user/getUserInfo, 其他接口全部放行。
5. 功能验证
5.1、申请TOKEN,获取JWT与TOKEN增强信息
1)设置Basic Auth认证信息
这里填入的是客户端模式的用户名和密码,并非认证用户信息。
2) 设置密码模式的请求参数信息
3) 请求返回结果
可以看到JWT的TOKEN信息, 以及增强设置中的ID和DATE信息。
5.2 、访问受保护的资源接口
1) 请求获取用户信息接口, 如果不传入TOKEN, 会提示无权访问
2) 传入TOKEN访问
能够正常访问接口, 注意, 传入的TOKEN要选择【Bearer Token】方式。
5.3、访问TOKEN信息
请求接口, 传入token参数: http://127.0.0.1:22619/oauth/check_token
可以看到JWT TOKEN的详细信息。
6. 总结
- 掌握Spring Boot 与Spring Security 和OATUH2的集成用法, 在微服务场景当中,也能够适用, 微服务应用中一般会接入网关进行统一鉴权,也可以由各资源服务再做鉴权处理 ,方式灵活多样, 大家可以再多做实践。
- 这里用到了OAUTH2的客户端模式和密码模式, 适合微服务场景大用户量的接入,采用Redis缓存, 能够保障较高的性能, JWT附带信息不能过多, 会增加传输资源开销, 加密方式也不能过于复杂, 影响CPU性能, 如果有较多额外信息需要传递, 可以采用TOKEN增强模式, 数据存储在缓存, 不会带来过多的IO开销。在实际项目当中, 要做仔细权衡,能加入缓存地方尽量加入, 保障安全的同时, 也要有较好的性能。
- 源码下载地址: https://download.csdn.net/download/hxx688/86400104
- 上一篇:EMQ X支持哪些认证方式?
- 下一篇:API接口安全设计方案(已实现)
相关推荐
- 【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...
- Pure Storage推出统一数据管理云平台及新闪存阵列
-
PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...
- 对Java学习的10条建议(对java课程的建议)
-
不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...
- SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!
-
官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...
- JDK21有没有什么稳定、简单又强势的特性?
-
佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...
- 「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了
-
在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...
- Java面试题及答案最全总结(2025版)
-
大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...
- 数据库日常运维工作内容(数据库日常运维 工作内容)
-
#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...
- 分布式之系统底层原理(上)(底层分布式技术)
-
作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...
- oracle 死锁了怎么办?kill 进程 直接上干货
-
1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...
- SpringBoot 各种分页查询方式详解(全网最全)
-
一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...
- 《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略
-
《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...
- LoadRunner(loadrunner录制不到脚本)
-
一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...
- Redis数据类型介绍(redis 数据类型)
-
介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...
- RMAN备份监控及优化总结(rman备份原理)
-
今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)