Oauth2.0 认证服务器搭建
核心 POM
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId><version>2.2.6.RELEASE</version>
</dependency>
配置 WebSecurityConfig 开启 Spring 方法级的安全保护
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;/*** 开启Spring方法级的安全保护*/
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {/*** 授权码模式在浏览器地址栏发起请求来获取 code* .anyRequest().authenticated() 必须对该请求进行认证拦截,发现用户没有登陆的时候会弹出登陆框, 从而让用户输入用户名和密码进行登陆, 若是对该请求进行放行, 则登陆页无法弹出, 并抛出 InsufficientAuthenticationException* .httpBasic() 因为用户未登陆访问了受保护的资源, 所以还要开启 httpBasic 进行简单认证, 否则会抛出 AccessDeniedException 异常,*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable()//关闭跨域保护.authorizeRequests().antMatchers("/captcha/**").permitAll().anyRequest().authenticated().and().httpBasic().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)//永远不会创建HttpSession, 默认配置.and().headers().cacheControl().disable()//禁用缓存;}/*** 注入一个认证管理器, 自身不实现身份验证, 而是逐一向认证提供者进行认证, 直到某一个认证提供者能够成功验证当前用户的身份* * AuthenticationManager(认证管理器接口) 的默认实现类 ProviderManager, 管理多个 AuthenticationProvider(认证提供者)*/@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}}
配置 TokenConfig 来定义 Token 的生成方式
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;/*** 配置token*/
@Configuration
public class TokenConfig {@Beanpublic TokenStore jwtTokenStore() {//令牌存储方案采用JWTreturn new JwtTokenStore(jwtAccessTokenConverter());}/** AccessToken转换器: 定义 token 的生成方式* JwtAccessTokenConverter: 表示采用 JWT 来生成*/@Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(OauthConstant.OAUTH_SIGNING_KEY); //对称秘钥,资源服务器使用该秘钥来验证return converter;}}
配置 UserDetailsService 和 JdbcClientDetailsService 获取用户和客户端信息
自定义客户端表结构
-- oauth2.0 默认有一套客户端表结构可进行替换,以下为自定义,其他用户的表结构就自行定义吧
CREATE TABLE `sys_client` (`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',`client_id` varchar(32) NOT NULL COMMENT '客户端ID',`resource_ids` varchar(256) DEFAULT NULL COMMENT '客户端密钥',`client_secret` varchar(256) DEFAULT NULL COMMENT '资源ID列表',`scope` varchar(256) DEFAULT NULL COMMENT '作用域',`authorized_grant_types` varchar(256) DEFAULT NULL COMMENT '授权方式',`web_server_redirect_uri` varchar(256) DEFAULT NULL COMMENT '回调地址',`authorities` varchar(256) DEFAULT NULL COMMENT '权限列表',`access_token_validity` int DEFAULT NULL COMMENT '令牌有效时间',`refresh_token_validity` int DEFAULT NULL COMMENT '刷新令牌有效时间',`additional_information` varchar(4096) DEFAULT NULL COMMENT '扩展信息',`autoapprove` varchar(256) DEFAULT NULL COMMENT '是否自动放行',`deleted` char(1) DEFAULT '0' COMMENT '删除标记,1:已删除,0:正常',`platform_id` int NOT NULL DEFAULT '0' COMMENT '所属平台',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='客户端信息表';-- 插入两条测试客户端
INSERT INTO `platform`.`sys_client`(`id`, `client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`, `deleted`, `platform_id`) VALUES (1, 'c1', '', '$2a$10$1Bg3qCxNVXobR2SJG9t0zOV45glOCH1MpvvPJDdyXCycWu/rZ1DOa', 'all', 'refresh_token,authorization_code,client_credentials,implicit', 'http://www.baidu.com', NULL, 72000, 259200, NULL, 'false', '0', 0);
INSERT INTO `platform`.`sys_client`(`id`, `client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`, `deleted`, `platform_id`) VALUES (2, 'c2', 'mo-wen-res', '$2a$10$1Bg3qCxNVXobR2SJG9t0zOV45glOCH1MpvvPJDdyXCycWu/rZ1DOa', 'all', 'password,refresh_token,captcha,authorization_code', 'http://www.baidu.com', NULL, 72000, 259200, NULL, 'false', '0', 0);
-- 查询客户端信息
String OAUTH_SQL_CLIENT = "SELECT client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove\n" +"FROM sys_client WHERE client_id = ? AND deleted = 0";-- 查询用户信息
String OAUTH_SQL_LOGIN_USER = "select user_id as id, `name`, phone, password from sys_user where phone = ?";-- 查询用户权限
String OAUTH_SQL_USER_PERMISSION = "SELECT `name` FROM sys_permission WHERE id IN(\n" +" SELECT permission_id FROM sys_role_permission WHERE role_id IN(\n" +" SELECT role_id FROM sys_user_role WHERE user_id = ?\n" +" )\n" +")";
定义 UserDetailsService 的实现类用于查询用户信息
@Slf4j
@Service
@AllArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {// 查询用户信息的service, 自行定义private final UserService userService;@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {LoginUser loginUser = userService.getUserByPhone(s);List<String> authorities = userService.getPermissionsByUserId(loginUser.getId());log.info("当前登陆用户: [{}] 权限: [{}]", loginUser, authorities);return User.withUsername(toJSONString(loginUser)).password(loginUser.getPassword()).authorities(authorities.toArray(new String[0])).build();}}
重写 JdbcClientDetailsService 用于查询客户端信息
@Slf4j
@Service
public class JdbcClientDetailsServiceImpl extends JdbcClientDetailsService {public JdbcClientDetailsServiceImpl(DataSource dataSource) {super(dataSource);}@Resourceprivate PasswordEncoder bCryptPasswordEncoder;@Overridepublic ClientDetails loadClientByClientId(String clientId) throws InvalidClientException {super.setSelectClientDetailsSql(OauthConstant.OAUTH_SQL_CLIENT);super.setPasswordEncoder(bCryptPasswordEncoder);ClientDetails clientDetails = super.loadClientByClientId(clientId);log.info("加载客户端信息: [{}], [{}]", clientId, clientDetails);return clientDetails;}//用于密码的加密方式@Beanpublic PasswordEncoder bCryptPasswordEncoder() {return new BCryptPasswordEncoder();}}
继承 AuthorizationServerConfigurerAdapter 来实现认证服务器的核心配置❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
@Configuration
@EnableAuthorizationServer
@AllArgsConstructor
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {private final JdbcClientDetailsServiceImpl clientDetailsServiceImpl;private final UserDetailsServiceImpl userDetailsServiceImpl;private final TokenStore jwtTokenStore;private final JwtAccessTokenConverter jwtAccessTokenConverter;private final AuthenticationManager authenticationManager;private final PasswordEncoder bCryptPasswordEncoder;private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;private final CustomWebResponseExceptionTranslator customWebResponseExceptionTranslator;/*** 用来配置令牌端点的安全约束, 密码校验方式等*/@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {security.allowFormAuthenticationForClients().passwordEncoder(bCryptPasswordEncoder).tokenKeyAccess("permitAll()") //oauth/token_key是公开.checkTokenAccess("permitAll()") //oauth/check_token公开;}/*** 用来配置客户端详情服务(ClientDetailsService), 客户端详情信息在这里进行初始化*/@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.withClientDetails(clientDetailsServiceImpl);}/*** 用来配置令牌(token)的访问端点和令牌服务* 配置令牌的访问端点:即申请令牌的URL .pathMapping(defaultPath, customPath)* 令牌服务:令牌的生成和发放规则(TokenConfig)*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.userDetailsService(userDetailsServiceImpl).authenticationManager(authenticationManager)//认证管理器,Password模式配置所需.authorizationCodeServices(authorizationCodeServices())//授权码模式code存储方式定义.tokenStore(jwtTokenStore)//采用jwt方式管理token.accessTokenConverter(jwtAccessTokenConverter)//jwt增强,定义自己的SigningKey.allowedTokenEndpointRequestMethods(HttpMethod.POST, HttpMethod.GET).reuseRefreshTokens(false)//表示重复使用刷新令牌。也就是说会一直重复使用第一次请求到的 refresh_token, 所以要禁止掉;}@Beanpublic AuthorizationCodeServices authorizationCodeServices() { //设置授权码模式的授权码如何存取,暂采用内存方式return new InMemoryAuthorizationCodeServices();}}
测试端口
- 获取 code:Get /oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com
- 简化模式获取 token:Get /oauth/authorize?response_type=token&client_id=c1&redirect_uri=http://www.baidu.com
- 密码模式获取 token:Post /oauth/token
- grant_type:password
- username:用户名
- password:密码
- Authorization:Basic YzI6NDU2 — 请求头添加客户端信息
- 授权码模式获取 token:Post /oauth/token
- grant_type:authorization_code
- code:获取到的 code
- redirect_uri:重定向url
- Authorization:Basic YzI6NDU2 — 请求头添加客户端信息
- 刷新 token:Post /oauth/token
- grant_type:refresh_token
- refresh_token:拿到获取token时得到的refresh_token
- Authorization:Basic YzI6NDU2 — 请求头添加客户端信息
Oauth2.0 系列文章
以下是同步到语雀的、可读性好一点,CSDN 继续看的点专栏就好。
Oauth2.0 核心篇
Oauth2.0 安全性(以微信授权登陆为例)
Oauth2.0 认证服务器搭建
Oauth2.0 添加验证码登陆方式
Oauth2.0 资源服务器搭建
Oauth2.0 自定义响应值以及异常处理
Oauth2.0 补充
Oauth2.0 认证服务器搭建相关推荐
- Spring Security OAuth2.0认证授权知识概括
Spring Security OAuth2.0认证授权知识概括 安全框架基本概念 基于Session的认证方式 Spring Security简介 SpringSecurity详解 分布式系统认证方 ...
- Spring Security OAuth2.0认证授权
文章目录 1.基本概念 1.1.什么是认证 1.2 什么是会话 1.3什么是授权 1.4授权的数据模型 1.4 RBAC 1.4.1 基于角色的访问控制 2.基于Session的认证方式 3.整合案例 ...
- SpringSecurity OAuth2.0认证授权-part2
此篇文章包含oauth2项目搭建.整合jwt.授权方式测试: 篇幅过长,拆分为: part1: 认证授权原理回顾及分布式系统认证方案: part2: oauth2项目搭建.授权方式测试: part3: ...
- Spring Security OAuth2.0认证授权三:使用JWT令牌
历史文章 [Spring Security OAuth2.0认证授权一:框架搭建和认证测试] [Spring Security OAuth2.0认证授权二:搭建资源服务] 前面两篇文章详细讲解了如何基 ...
- 【django】用户登录模块实现步骤(二)之QQ登录工具AgentLogin和通过OAuth2.0认证获取openid【33】
一.QQ登录工具AgentLogin 1.AgentLogin介绍 ⽬前只⽀持 腾讯QQ,微信,微博的第三⽅登录 该⼯具封装了QQ登录时对接QQ互联接⼝的请求操作.可⽤于快速实现QQ登录功能. 2.A ...
- Spring Security OAuth2.0认证授权五:用户信息扩展到jwt
历史文章 [Spring Security OAuth2.0认证授权一:框架搭建和认证测试] [Spring Security OAuth2.0认证授权二:搭建资源服务] [Spring Securi ...
- 如何支持微软邮箱OAuth2.0认证
近期收到部分使用微软邮箱的客户反映,在EDI系统中无法连接到他们的企业邮箱中,连接过程中报错: IMAP protocol error. 1 NO LOGIN failed-,经确认是微软停用了邮箱的 ...
- C# 网络编程之豆瓣OAuth2.0认证具体解释和遇到的各种问题及解决
近期在帮人弄一个豆瓣API应用,在豆瓣的OAuth2.0认证过程中遇到了各种问题,同一时候自己须要一个个的尝试与解决,终于完毕了豆瓣API的訪问.作者这里就不再吐槽豆瓣的认证文档了,毕 ...
- C# 网络编程之豆瓣OAuth2.0认证详解和遇到的各种问题及解决
最近在帮人弄一个豆瓣API应用,在豆瓣的OAuth2.0认证过程中遇到了各种问题,同时自己需要一个个的尝试与解决,最终完成了豆瓣API的访问.作者这里就不再吐槽豆瓣的认证文档了,毕竟人 ...
最新文章
- (十二)企业级java springcloud b2bc商城系统开源源码二次开发-断路器监控(Hystrix Dashboard)...
- 提取图像数据的特征,让机器“看见”
- Codeforces Round #674 (Div. 3)
- maven java1.7_本周Java技巧#7 – Maven慢吗?
- mysql dump 1017_MySQL数据库导出 - Can't Wait Any Longer - OSCHINA - 中文开源技术交流社区...
- 《Python Cookbook 3rd》笔记(5.11):文件路径名的操作
- linux ip 访问记录,linux 精确记录用户IP以及用户操作命令
- 【Redis】redis 主从复制
- python123m与n的数学运算_python小白进阶之路三——循环结构入门练习+Random库练习...
- JavaWeb——eclipse与tomcat环境配置
- jmeter配置元件之计数器
- pg数据库表接口和数据导出
- C#6.0VISUALSTUDIO 2015 C#入门经典 第7版pdf
- 怎么将服务器中图片显示出来,服务器显示图片
- iOS迅雷V6.01更新,变化重大丨附下载地址
- mysql 误删除数据恢复
- 10008---光环效应
- JZOJ7月28日提高组反思
- openwrt + dnsmasq + anti-AD 两步搞定广告屏蔽
- Python-3:循环-练习
热门文章
- 100道Java实习生需要掌握的面试问题
- js实现飞机大战小游戏
- Intel Tick-Tock
- CodeSmith 4 Release 注册破解序列号注册码方法
- MSA应用――MSA手册第四版的新亮点
- [JVM] java虚拟机内存管理机制及垃圾收集
- 旺店通·企业奇门与金蝶云星空对接集成查询货品档案连通物料新增(旺店通物料对接金蝶物料)
- WPF自定义列中按钮的IsEnabled属性根据列中的值的不同动态赋值
- 达内出来的混得怎么样了_大学经验丨计算机专业学生,应该怎么样才不会沦为普通程序员?...
- 如何解决win10网络出现叹号,但是能连网问题