Springboot+oauth2.0实现微信登录(oauth2.0自定义授权模式)
1、前置准备参考 https://blog.csdn.net/qq_34190023/article/details/81133619
2、微信登录实现流程图
3、oauth自定义授权模式
上图大概描述了微信登录的一个流程。如果你是用oauth2.0,就会存在一个问题。oauth2.0自身支持四种授权模式,分别是:
- authorization code(授权码模式)
- implicit(简化模式)
- resource owner password credentials(密码模式)
- client credentials(客户端模式)
前三种模式都需要用户的密码才能认证成功,客户端模式虽然不需要密码,但是也不会跟用户绑定。所以也是不符合的。我们去微信拿到用户的认证之后,需要自己的系统认证通过,然后返回token给前端。如果系统采用oauth2.0来做认证,这时候我们是没办法拿到用户的明文密码的。并且一般密码都是用BCryptPasswordEncoder加密处理,是不可逆的。这个时候,我们虽然通过了微信的认证,但是如何通过自身系统的认证就是个问题了。那么这时候就需要自定义oauth2.0的授权模式了,通过微信返回的用户唯一标识来完成认证。
注:自定义授权模式适用于任何第三方登录
附上核心代码:
/**** 第三方登录验证filter*/
public class SocialAuthenticationFilter extends AbstractAuthenticationProcessingFilter {private static final String SPRING_SECURITY_FORM_MOBILE_KEY = "social";@Getter@Setterprivate String mobileParameter = SPRING_SECURITY_FORM_MOBILE_KEY;@Getter@Setterprivate boolean postOnly = true;@Getter@Setterprivate AuthenticationEventPublisher eventPublisher;@Getter@Setterprivate AuthenticationEntryPoint authenticationEntryPoint;public SocialAuthenticationFilter() {super(new AntPathRequestMatcher("/social/token", "POST"));}@Override@SneakyThrowspublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());}String mobile = obtainMobile(request);if (mobile == null) {mobile = "";}mobile = mobile.trim();SocialAuthenticationToken socialAuthenticationToken = new SocialAuthenticationToken(mobile);setDetails(request, socialAuthenticationToken);Authentication authResult = null;try {authResult = this.getAuthenticationManager().authenticate(socialAuthenticationToken);logger.debug("Authentication success: " + authResult);SecurityContextHolder.getContext().setAuthentication(authResult);}catch (Exception failed) {SecurityContextHolder.clearContext();logger.debug("Authentication request failed: " + failed);eventPublisher.publishAuthenticationFailure(new BadCredentialsException(failed.getMessage(), failed),new PreAuthenticatedAuthenticationToken("access-token", "N/A"));try {authenticationEntryPoint.commence(request, response,new UsernameNotFoundException(failed.getMessage(), failed));}catch (Exception e) {logger.error("authenticationEntryPoint handle error:{}", failed);}}return authResult;}private String obtainMobile(HttpServletRequest request) {return request.getParameter(mobileParameter);}private void setDetails(HttpServletRequest request, SocialAuthenticationToken authRequest) {authRequest.setDetails(authenticationDetailsSource.buildDetails(request));}}
/*** 社交登录*/
@Slf4j
public class SocialAuthenticationProvider implements AuthenticationProvider {private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();private UserDetailsChecker detailsChecker = new PreAuthenticationChecks();@Getter@Setterprivate UserDetailsService socialUserDetailService;@Override@SneakyThrowspublic Authentication authenticate(Authentication authentication) {SocialAuthenticationToken socialAuthenticationToken = (SocialAuthenticationToken) authentication;String principal = socialAuthenticationToken.getPrincipal().toString();UserDetails userDetails = socialUserDetailService.loadUserByUsername(principal);if (userDetails == null) {log.debug("Authentication failed: no credentials provided");throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.noopBindAccount", "Noop Bind Account"));}// 检查账号状态detailsChecker.check(userDetails);SocialAuthenticationToken authenticationToken = new SocialAuthenticationToken(userDetails,userDetails.getAuthorities());authenticationToken.setDetails(socialAuthenticationToken.getDetails());return authenticationToken;}@Overridepublic boolean supports(Class<?> authentication) {return SocialAuthenticationToken.class.isAssignableFrom(authentication);}}
/*** 第三方登录令牌*/
public class SocialAuthenticationToken extends AbstractAuthenticationToken {private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;private final Object principal;public SocialAuthenticationToken(String mobile) {super(null);this.principal = mobile;setAuthenticated(false);}public SocialAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {super(authorities);this.principal = principal;super.setAuthenticated(true);}@Overridepublic Object getPrincipal() {return this.principal;}@Overridepublic Object getCredentials() {return null;}@Override@SneakyThrowspublic void setAuthenticated(boolean isAuthenticated) {if (isAuthenticated) {throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");}super.setAuthenticated(false);}@Overridepublic void eraseCredentials() {super.eraseCredentials();}}
/**** 第三方登录配置入口*/
@Getter
@Setter
public class SocialSecurityConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {@Autowiredprivate ObjectMapper objectMapper;@Autowiredprivate AuthenticationEventPublisher defaultAuthenticationEventPublisher;@Autowiredprivate AuthenticationSuccessHandler socialLoginSuccessHandler;@Autowiredprivate UserDetailsService socialUserDetailService;@Overridepublic void configure(HttpSecurity http) {SocialAuthenticationFilter socialAuthenticationFilter = new SocialAuthenticationFilter();socialAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));socialAuthenticationFilter.setAuthenticationSuccessHandler(socialLoginSuccessHandler);socialAuthenticationFilter.setEventPublisher(defaultAuthenticationEventPublisher);socialAuthenticationFilter.setAuthenticationEntryPoint(new ResourceAuthExceptionEntryPoint(objectMapper));SocialAuthenticationProvider socialAuthenticationProvider = new SocialAuthenticationProvider();socialAuthenticationProvider.setSocialUserDetailService(socialUserDetailService);http.authenticationProvider(socialAuthenticationProvider).addFilterAfter(socialAuthenticationFilter,UsernamePasswordAuthenticationFilter.class);}}
@Slf4j
public class PreAuthenticationChecks implements UserDetailsChecker {private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();@Overridepublic void check(UserDetails user) {if (!user.isAccountNonLocked()) {log.debug("User account is locked");throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked", "User account is locked"));}if (!user.isEnabled()) {log.debug("User account is disabled");throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled", "User is disabled"));}if (!user.isAccountNonExpired()) {log.debug("User account is expired");throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired","User account has expired"));}}}
附上测试请求示例:code对应微信返回用户唯一标识。即可完成本系统认证,拿到token。
Map<String, Object> params = new HashMap<>();
params.put("grant_type","social");
params.put("social",code);
params.put("client_id","test");
params.put("client_secret","test");
String token = OkHttpUtils.doFromPost("http://localhost:端口号/auth/social/token", params);
Springboot+oauth2.0实现微信登录(oauth2.0自定义授权模式)相关推荐
- .net Core2.2 WebApi通过OAuth2.0实现微信登录
前言 微信相关配置请参考 微信公众平台 的这篇文章.注意授权回调域名一定要修改正确. 微信网页授权是通过OAuth2.0机制实现的,所以我们可以使用 https://github.com/china- ...
- Spring Security OAuth2 微服务认证中心自定义授权模式扩展以及常见登录认证场景下的应用实战
本文源码地址 后端:https://gitee.com/youlaitech/youlai-mall/tree/v2.0.1 前端:https://gitee.com/youlaiorg/mall-a ...
- SpringBoot整合小程序微信登录功能
一.SpringBoot整合微信登录 小程序的使用已经是一个普遍的现象,对于刚学习SpringBoot的我们来说完全的写好一套微信登录的案例有一定的难度,这里结合自己的一些学习经验,把微信登录这一 ...
- 微信android最新版本,安卓微信怎么升级为最新版微信8.0 安卓微信升级8.0方法
安卓微信怎么升级 微信发布了最新版微信8.0.与以往不同的是,作为一款已风靡十年的社交产品,微信此次版本更新带来许多全新玩法和小创意. 目前苹果手机用户可以点击"关于微信"进行自动 ...
- Spring Security Oauth2 如何增加自定义授权模式
在 oauth2 中已经默认有的授权模式中有4种: 授权码模式 隐式授权模式 密码模式 客户端模式 但是实际使用过程中万一我们要基于短信授权,或者基于token 直接授权该怎么办? 这里我们可以先看下 ...
- 清除微信登录历史、自定义默认文件保存位置以及聊天记录还原
这篇文章的本意呢,其实对个人用户意义不大,因为桌面端微信本身提供了自定义用户数据文件存放路径的设置项,那么为什么要写出来这么一篇看似无用的教程来呢?是因为微信本身的特殊性,需要用户登录以后才可以修改设 ...
- mysql8.0新建用户登录_Mysql8.0 创建远程登陆账户
mysql8和原来的版本有点不一样,8的安全级别更高,所以在创建远程连接用户的时候, 不能用原来的命令(同时创建用户和赋权): mysql>grant all PRIVILEGES on *.* ...
- android11 第三方微信登录、分享无法授权解决方案
根据 Android 官方给出的适配方案,在主工程的AndroidManifest.xml 中增加 标签,即可解决以上影响,代码如下 <manifest package="com.ex ...
- oauth2.0与单点登录
1.什么是 OAuth2.0 OAuth (Open Authority的缩写)是一个开放标准,该标准允许用户让第三方应用访问该用户在某一网站上存储的私密资源(如头像.照片.视频等),而在这个过程中无 ...
最新文章
- python 列表生成器 获取文件列表
- 设计模式之间的关联关系和对比
- 怎样下载C/C++的免费、开源且跨平台IDE——Code::Blocks
- 对麦克纳姆轮辊子的理解
- 传智播客 java视频_java传智播客视频
- Laravel单元测试
- [Windows] 翻页时钟Fliqlo 1.4 — 无需Flash Player,2021年官网最新更新 ,fliqlo 时钟屏保不显示了怎么办?已解决!
- eNSP华为路由器与交换机连接
- android登录实现回显用户名和密码
- 移动端H5页面关于软键盘的一些踩坑记录
- 数据机房特殊规范标签生成及打印方案分享
- 高中生用台灯哪种好?2023最好的台灯品牌排行榜
- jQuery表格导出Excel文件以及网页内容导出Word文档
- 为什么重写equals方法时一定要重写hashCode方法
- 基于遥感影像的道路提取论文、开源代码和数据集汇总
- 5G商用元年车联网鏖战升级 谁能掌握最后的话语权?
- append()函数
- 架设传奇私服时提示此服务器满员的解决方法
- eNSP之IPsec 虚拟专用网配置
- mysql 发生系统错误1067的解决方法
热门文章
- Mac打不开别人的.one文件
- 添加或修改Kindle图书封面
- 六级考研单词之路-十一
- 在 FPGA 上快速构建 PID 算法
- #loj3124. 「CTS2019 | CTSC2019」氪金手游
- latex参考文献居中_latex参考文献常见问题
- 你的脸正在成为别人的生意!
- 基于Redis的分布式锁真的安全吗?
- 穿上钢铁侠战衣变身钢铁侠,现代表示我做到了!
- 教育资源平台空间装扮html代码,一看就会—— 河南省基础教育资源公共服务平台“人人通空间”...