OAuth 2.0授权框架支持第三方支持访问有限的HTTP服务,通过在资源所有者和HTTP服务之间进行一个批准交互来代表资源者去访问这些资源,或者通过允许第三方应用程序以自己的名义获取访问权限。

1.认证授权服务配置

主要配置继承AuthorizationServerConfigurerAdapter的三个配置,其他的属于配置类中方法或参数的加强和修饰。

package com.panda.admin.login.authconfig;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
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.redis.RedisTokenStore;import java.util.Arrays;/*** author: tcy* createDate: 2022/10/26* description:认证授权服务配置*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate ClientDetailsService clientDetailsService;@Autowiredprivate SysUserDetailServiceImpl sysUserDetailService;/*** redis工厂*/@Autowiredprivate RedisConnectionFactory redisConnectionFactory;/*** 用来配置令牌的安全约束* 拦截控制*/@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) {security.checkTokenAccess("permitAll()")                                 // check_token公开.tokenKeyAccess("permitAll()")                                   // token_key公开.allowFormAuthenticationForClients();                            // 表单认证(申请令牌)}/*** 用来配置客户端详情服务(ClientDetailsService)* 允许客户端自己申请ClientID*/@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {/*** 数据库中添加客户端信息表,可以启用withClientDetails* 还需要自己建立ClientDetailsService的实现类ClientDetailsServiceImpl* ClientDetailsServiceImpl implements ClientDetailsService* 在实现类中将客户端相关数据配置好*///clients.withClientDetails(clientDetailsService);/*** 客户端配置唯一,直接在代码中配置也可以* 但是保密性不强,安全性不高*/clients.inMemory().withClient("client")                                               //注册客户端id.secret(passwordEncoder.encode("secret"))                      //注册客户端密码.accessTokenValiditySeconds(60)                                            //有效时间60秒,测试阶段容易看出效果.authorizedGrantTypes("authorization_code","password","refresh_token")     //三方登录、密码授权、刷新令牌.autoApprove(true)                                                         //登录后绕过批准询问(/oauth/confirm_access).scopes("all")                                                             //允许授权范围.redirectUris("https://gitee.com/");                                       //回调网址,携带授权码}/*** 管理令牌:用来配置令牌(token)的访问端点和令牌服务(token services)*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {//token增强TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));endpoints.authenticationManager(authenticationManager).accessTokenConverter(jwtAccessTokenConverter()).tokenStore(tokenStore()).tokenEnhancer(tokenEnhancerChain)/** refresh token有两种使用方式:重复使用(true)、非重复使用(false),默认为true*  1 重复使用:access token过期刷新时, refresh token过期时间未改变,仍以初次生成的时间为准*  2 非重复使用:access token过期刷新时, refresh token过期时间延续,在refresh token有效期内刷新便永不失效达到无需再次登录的目的*/.reuseRefreshTokens(true).userDetailsService(sysUserDetailService);}/*** 自定义的Token增强器,把更多信息放入Token中* 登录者的id、角色、手机号、其他绑定账号等*/@Beanpublic TokenEnhancer tokenEnhancer() {return new EnhanceTokenEnhancer();}/*** 配置JWT令牌*/@Beanprotected JwtAccessTokenConverter jwtAccessTokenConverter() {//设置jwt的转换器JwtAccessTokenConverter converter = new JwtAccessTokenConverter();/*** 非对称加密:密钥库中获取密钥对(公钥+私钥)* 需要 *.jks文件*///KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jks/jwt.jks"), "123456".toCharArray());//KeyPair keyPair = keyStoreKeyFactory.getKeyPair("jwt","888888".toCharArray());             //设置获取秘钥的密码//converter.setKeyPair(keyPair);                                                             //设置秘钥对象/*** 对称加密*/converter.setSigningKey("Tu");return converter;}/*** JWT令牌存储*/@Beanpublic TokenStore tokenStore() {/*** springSecurity中TokenStore实现有4种,分别是:*    InMemoryTokenStore(保存本地内存)*    JdbcTokenStore(保存到数据库)*    JwkTokenStore(全部信息返回到客户端)*    RedisTokenStore(保存到redis)*///存放至redis库,注意pom和yml中相关配置RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);redisTokenStore.setPrefix("auth:token:access:");return redisTokenStore;//return new JwtTokenStore(jwtAccessTokenConverter());}}

2.安全配置

主要为密码、身份认证、请求放行

package com.panda.admin.login.authconfig;import com.panda.admin.login.auth.service.impl.SysUserDetailServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;import javax.annotation.Resource;/*** author: tcy* createDate: 2022/10/27* description:安全配置*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate SysUserDetailServiceImpl sysUserDetailService;/*** 密码编码器** 委托方式,根据密码的前缀选择对应的encoder,* 例如:{bcypt}前缀->标识BCYPT算法加密;*     {noop}->标识不使用任何加密即明文的方式*/@Beanpublic PasswordEncoder passwordEncoder() {//秘文编辑密码//return new BCryptPasswordEncoder();//编辑工厂,可用多种方式编辑return PasswordEncoderFactories.createDelegatingPasswordEncoder();}/*** 认证管理器*/@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}/*** 身份验证管理器*/@Overridepublic void configure(AuthenticationManagerBuilder auth) throws Exception {/*** 测试用户,单独提供* 只能用这个用户才能登录*///auth.inMemoryAuthentication()//    .withUser("panda")//    .password(passwordEncoder().encode("123456"))//    .roles("admin");/*** 这里从数据库查询用户,但是登录方式唯一*///auth.userDetailsService(sysUserDetailService);/*** 可以匹配多种登录方式* 账号密码、手机验证码、第三方授权等*/auth.authenticationProvider(daoAuthenticationProvider());}/*** 账号密码 认证授权提供者*/@Beanpublic DaoAuthenticationProvider daoAuthenticationProvider(){DaoAuthenticationProvider provider = new DaoAuthenticationProvider();provider.setUserDetailsService(sysUserDetailService);provider.setPasswordEncoder(passwordEncoder());provider.setHideUserNotFoundExceptions(false);  //是否隐藏用户不存在异常return provider;}/*** 配置放行规则*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/oauth/**").permitAll().antMatchers("/login/**").permitAll().antMatchers("/webjars/**", "/doc.html", "/swagger-resources", "/v2/api-docs","swagger-ui.html").permitAll().antMatchers("/actuator/**","/instances/**").permitAll().anyRequest().authenticated().and().csrf().disable();}@Override@Beanpublic UserDetailsService userDetailsService(){return super.userDetailsService();}
}

3.token增强

这部分可以直接放在AuthorizationServerConfig的token增强器中

package com.panda.admin.login.authconfig;import com.panda.admin.login.constant.SecurityConstants;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;import java.util.HashMap;
import java.util.Map;/*** author: tcy* createDate: 2022/10/26* description:Token增强器*/
public class EnhanceTokenEnhancer implements TokenEnhancer {@Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {Authentication userAuthentication = oAuth2Authentication.getUserAuthentication();if (userAuthentication != null) {Map<String, Object> additionalInfo = new HashMap<>();additionalInfo.put(SecurityConstants.DETAILS_USER_ID, 2629738803L);additionalInfo.put(SecurityConstants.DETAILS_USERNAME, "承天永明");additionalInfo.put(SecurityConstants.DETAILS_NICKNAME, "飒飒");additionalInfo.put(SecurityConstants.OPEN_ID, "123456789");additionalInfo.put(SecurityConstants.ROLE_ID, "1");additionalInfo.put(SecurityConstants.MOBILE, "19108217140");((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(additionalInfo);}return oAuth2AccessToken;}
}

4.登录客户的信息

package com.panda.admin.login.auth.Details;import com.panda.admin.login.SystemUser;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import java.io.Serializable;
import java.util.Collection;/*** author: tcy* createDate: 2022/11/9* description:系统管理用户认证信息*/
@Data
public class SysUserDetails implements UserDetails, Serializable {private static final long serialVersionUID = 1L;private Long id;private String nickName;/*** UserDetails默认字段*/private String username;private String password;private Collection<SimpleGrantedAuthority> authorities;public SysUserDetails(SystemUser user){this.setId(user.getId());this.setUsername(user.getNickname());//数据表中,账号为account字段this.setUsername(user.getAccount());this.setPassword(user.getPassword());}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return this.authorities;}//获取密码@Overridepublic String getPassword() {return this.password;}//获取用户名@Overridepublic String getUsername() {return this.username;}//账号是否可用@Overridepublic boolean isAccountNonExpired() {return true;}//账号是否锁定@Overridepublic boolean isAccountNonLocked() {return true;}//凭证是否过期@Overridepublic boolean isCredentialsNonExpired() {return true;}//用户是否正常@Overridepublic boolean isEnabled() {return true;}
}

5.系统用户信息查询

package com.panda.admin.login.auth.service.impl;import cn.hutool.core.util.ObjectUtil;
import com.panda.admin.login.SystemUser;
import com.panda.admin.login.auth.Details.SysUserDetails;
import com.panda.admin.result.ServiceException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;import javax.annotation.Resource;/*** author: tcy* createDate: 2022/11/9* description:系统用户信息*/
@Service
public class SysUserDetailServiceImpl implements UserDetailsService {@Resourceprivate SystemUserServiceImpl systemUserService;/*** 账号密码 认证*/@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {SysUserDetails sysUserDetails = null;//查询用户存在SystemUser systemUser = this.systemUserService.lambdaQuery().eq(SystemUser::getAccount, username).one();if (ObjectUtil.isNotEmpty(systemUser)){sysUserDetails = new SysUserDetails(systemUser);}if (ObjectUtils.isEmpty(systemUser) || ObjectUtils.isEmpty(sysUserDetails)){throw new ServiceException("用户不存在");}return sysUserDetails;}
}

6.明文密码获取token

/token/oauth接口是oauth2配置自带,不用建立相关接口,只需要模块的本地接口对上

(1)在用户表中创建用户数据,密码为明文

(2)在系统用户信息SysUserDetailServiceImpl中添加以下内容,{noop}表示不加密

if (ObjectUtil.isNotEmpty(systemUser)){systemUser.setPassword("{noop}" + systemUser.getPassword());sysUserDetails = new SysUserDetails(systemUser);
}

(3)使用apifox,配置用户信息,配置客户端信息,然后发送请求

得到的结果:

7.建立秘文密码用户数据

(1)建立秘文接口

package com.panda.admin.login.auth.controller;import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** author: tcy* createDate: 2022/11/9* description:*/
@Api(tags = "安全")
@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate PasswordEncoder passwordEncoder;@PostMapping("/info")public String info(){String secret = passwordEncoder.encode("tcy510823");return secret;}
}

(2)apifox中建立相关请求,将第6步获取的token放在请求头Authorization中,注意:bearer + token。

(3)复制秘文密码,在数据库中建立用户数据

8.秘文密码获取token

(1)去掉SysUserDetailServiceImpl中的不加密操作

systemUser.setPassword("{noop}" + systemUser.getPassword());

(2)更换用户信息发送请求

9.校验token

(1)/oauth/check_token为oauth2自带接口

(2)可以加工,得到适合的反馈效果

@Api(tags = "oauth登录安全")
@RestController
@RequestMapping("/oauth")
public class SystemUserController {@AutowiredTokenStore tokenStore;@ApiOperation(value = "校验token")@GetMapping("/check_token")public Result<String> checkToken(@RequestParam("token") String token) {OAuth2AccessToken oAuth2AccessToken = this.tokenStore.readAccessToken(token);if (ObjectUtils.isEmpty(oAuth2AccessToken) || oAuth2AccessToken.isExpired()){throw new ServiceException("token无法识别或已经过期");}OAuth2Authentication oAuth2Authentication = this.tokenStore.readAuthentication(token);if (ObjectUtils.isEmpty(oAuth2Authentication)){throw new ServiceException("验证信息无效或已过期");}int expiresIn = oAuth2AccessToken.getExpiresIn();return Result.success("token校验通过,有效时间:" + expiresIn + "s");}}

(3)复制上面得到的token,放入请求参数中

(4)结果

10.刷新token

(1)使用http://localhost:9001/oauth/token接口

(2)grant_type需要换成refresh_token

(3)refresh_token的值为之前请求,获取的refresh_token

(4)结果,注意:"expires_in": 59

oauth2单点登录总结相关推荐

  1. oauth2 单点登录_Spring Security Oauth2和Spring Boot实现单点登录

    最近在学习单点登录相关,调查了一下目前流行的单点登录解决方案:cas 和 oauth2,文章主要介绍oauth2 单点登录.希望这篇文章能帮助大家学习相关内容. 我们将使用两个单独的应用程序: 授权服 ...

  2. Spring Security OAuth2 单点登录和登出

    文章目录 1. 单点登录 1.1 使用内存保存客户端和用户信息 1.1.1 认证中心 auth-server 1.1.2 子系统 service-1 1.1.3 测试 1.2 使用数据库保存客户端和用 ...

  3. 【Spring Boot】Spring Boot @EnableOAuth2Sso | 启用 OAuth2 单点登录

    文章目录 演示工具版本 Maven 依赖 使用 @EnableOAuth2Sso OAuth2 配置 登出 完整示例 输出 参考文献 源码下载 本页将介绍Spring Security OAuth2 ...

  4. oauth2 单点登录_六个高Star开源项目,让你更懂OAuth和单点登录

    现在大部分的网络应用,登录.注册.密码加密保存.token 管理等功能都是必要的.为了让用户的隐私更能得到保障,使用起来更方便,OAuth 协议和单点登录系统也就应运而生.今天 Gitee 介绍的六款 ...

  5. Spring Security Oauth2 单点登录案例实现和执行流程剖析

    我已经试过了 教程很完美 Spring Security Oauth2 OAuth是一个关于授权的开放网络标准,在全世界得到的广泛的应用,目前是2.0的版本.OAuth2在"客户端" ...

  6. Spring Security OAuth2 单点登录

    1. 概述 在前面的文章中,我们学习了 Spring Security OAuth 的简单使用. <Spring Security OAuth2 入门> <Spring Securi ...

  7. (二)spring security:使用 OAuth2 SSO 实现单点登录

    一.前言 也许,我应该延续上一篇"(一)spring security:能做什么?"接着写,比如:如何实现RBAC权限动态控制.后端"验证码"生成与校验.JWT ...

  8. Gitlab集成odoo单点登录

    Gitlab集成odoo单点登录 1.Gitlab使用oauth2单点登录的背景 OAuth代表资源所有者向客户端应用程序提供对服务器资源的"安全委派访问".实际上,OAuth允许 ...

  9. Spring Cloud云架构 - SSO单点登录之OAuth2.0登录流程(2)

    上一篇是站在巨人的肩膀上去研究OAuth2.0,也是为了快速帮助大家认识OAuth2.0,闲话少说,我根据框架中OAuth2.0的使用总结,画了一个简单的流程图(根据用户名+密码实现OAuth2.0的 ...

最新文章

  1. 什么样的python程序员好找工作-Python学到什么程度才可以去找工作?掌握这4点足够了!...
  2. 高阶产品经理的自我修养:项目管理之启动
  3. keyup常用事件_keyup事件问题
  4. PID1 / 明明的随机数
  5. Web前端笔记-js中加载图片文件(vue cli中同样适用)
  6. ZooKeeper JMX
  7. MyBatis当多个请求参数时处理方式
  8. python和java的区别-三分钟看懂Python和Java的区别
  9. 安装完毕后VS2012(2013)中找不到ADO.NET Entity Data Model模板或 sql server database project模板
  10. window xp 自动关机命令
  11. android锁屏壁纸设置,安卓锁屏壁纸怎么换 安卓锁屏壁纸设置教程
  12. spring boot 报 http 406多种原因问题解决的总结
  13. UNITY TMP PRO 字体制作
  14. flutter 学习之项目一
  15. VirtulBox安装虚拟机(鼠标点击时)0x00000000指令引用的0x00000000内存该内存不能为written错误解决方案
  16. dynamix判定_音乐游戏中判定严格的意义何在?
  17. QLineEdit光标往左或者往右
  18. IT人职业道德的反思
  19. 几何画板用迭代法作图的技巧
  20. C#(三十二)之Windows绘图

热门文章

  1. 快递在线下单API接口
  2. Linux WiFi使用
  3. python的复数的实部虚部都是浮点数吗_python中复数的共轭复数知识点总结
  4. 可视化丨用数据分析福尔摩斯探案集
  5. SSM网上校园订餐系统-javaweb, mysql
  6. Linux Socket详解 大全 基础知识
  7. UBUNTU16.04使用CornerNet_Lite进行目标识别并嵌入到ROS中
  8. C#命名空间 System.IO思维导图
  9. 火狐网页访问https提示安全连接失败
  10. c语言求等差数列的和oj,华为oj之等差数列前n项和