Spring Boot + Spring Security + JWT + 微信小程序登录整合教程

参考文章

文章目录

  • 整合思想
  • 整合步骤
    • 1. AuthenticationToken
    • 2. AuthenticationProcessingFilter
    • 3. AuthenticationManager
    • 4. JWTFilter
    • 5. AuthenticationEntryPoint
    • 6. AuthenticationSuccessHandler
    • 7. 全局异常捕获
    • 8. WebSecurityConfig
    • 9. 开启全局方法安全

整合思想

  1. 自定义AuthenticationToken,封装登录的相关信息,用于SecurityContext存储和验证过程
  2. 自定义AuthenticationProcessingFilter,代替默认的UsernamePasswordAuthenticationFilter
    1. 使用code获取open_id、session_key等
    2. 将获取到的open_id、session_key等封装成一个未认证的AuthenticationToken,传递到AuthenticationManager
  3. AuthenticationManager执行认证授权过程
    1. 查询数据库,获取用户信息
    2. 没有用户则写入用户
    3. 使用用户信息获取角色
    4. 封装授权信息
    5. 将相关信息封装成一个已认证的AuthenticationToken,这个AuthenticationToken会传递到AuthenticationSuccessHandler(认证成功的处理方法)
  4. 配置Spring Security配置,将UsernamePasswordAuthenticationFilter替换成自定义的AuthenticationProcessingFilter
  5. 在自定义的AuthenticationProcessingFilter之前添加JWTFilter

整合步骤

1. AuthenticationToken

用于存储微信小程序登录信息

@Getter
@Setter
@ToString
public class WxAppletAuthenticationToken extends AbstractAuthenticationToken {private String openId;private Long userId;private String sessionKey;private String rawData;private String signature;private String role;// 使用openid和sessionKey创建一个未验证的tokenpublic WxAppletAuthenticationToken(String openId, String sessionKey, String role) {super(null);this.openId = openId;this.sessionKey = sessionKey;this.role = role;}// 使用openid和sessionKey创建一个已验证的tokenpublic WxAppletAuthenticationToken(String openId, String sessionKey, Long userId, Collection<? extends GrantedAuthority> authorities) {super(authorities);this.openId = openId;this.userId = userId;this.sessionKey = sessionKey;super.setAuthenticated(true);}// 使用openid创建一个已验证的tokenpublic WxAppletAuthenticationToken(String openId, Long userId, Collection<? extends GrantedAuthority> authorities) {super(authorities);this.openId = openId;this.userId = userId;super.setAuthenticated(true);}@Overridepublic Object getCredentials() {return this.openId;}@Overridepublic Object getPrincipal() {return this.sessionKey;}public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {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();}
}

2. AuthenticationProcessingFilter

用于匹配的请求

@Slf4j
public class WxAppletAuthenticationFilter extends AbstractAuthenticationProcessingFilter {public WxAppletAuthenticationFilter(String defaultFilterProcessesUrl) {super(defaultFilterProcessesUrl);}@Overridepublic Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {String method = httpServletRequest.getMethod().toUpperCase();if (!"POST".equals(method)) {throw new UnSupportMethodException(method);}String contentType = httpServletRequest.getContentType().toLowerCase();if ("application/json;charset=utf-8".equals(contentType)) {throw new UnSupportContentTypeException(contentType);}// body参数转换为jsonStringBuffer sb = new StringBuffer();String line = null;BufferedReader reader = httpServletRequest.getReader();while ((line = reader.readLine()) != null)sb.append(line);String jsonString = sb.toString().replaceAll("\\s", "").replaceAll("\n", "");JSONObject jsonObject = JSONUtil.parseObj(jsonString);// 取出codeString code = jsonObject.get("code", String.class);if (ObjectUtil.isEmpty(code)) {throw new MissingParameterException("code");}String role = jsonObject.get("role", String.class);if (ObjectUtil.isEmpty(role)) {throw new MissingParameterException("role");}JSONObject session = WeChatUtils.code2Session(code);String openId = session.get("openid", String.class);String sessionKey = session.get("session_key", String.class);if (ObjectUtil.isEmpty(openId) || ObjectUtil.isEmpty(sessionKey)) {throw new RuntimeException("无法获取openId");}return this.getAuthenticationManager().authenticate(new WxAppletAuthenticationToken(openId, sessionKey , role));}
}

3. AuthenticationManager

真正执行认证逻辑的manager

@Slf4j
@Component
public class WxAppletAuthenticationManager implements AuthenticationManager {@Resourceprivate UserService userService;@Resourceprivate UserRoleService userRoleService;@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {WxAppletAuthenticationToken token = null;if (authentication instanceof WxAppletAuthenticationToken) {token = (WxAppletAuthenticationToken) authentication;}User user = userService.getByOpenId(token.getOpenId());if (ObjectUtil.isEmpty(user)) {// 写入角色Integer roleId = RoleUtils.getRoleId(token.getRole());if (ObjectUtil.isEmpty(roleId)) {// 参数的角色不在列表中throw new RuntimeException("注册失败:" + token.toString());}// 注册账号user = userService.registry(token.getOpenId(), roleId.intValue());if (ObjectUtil.isEmpty(user)) {// 注册失败throw new RuntimeException("注册失败:" + token.toString());}}// 获取权限List<UserRoleVO> userRoleVOList = userRoleService.getByUserId(user.getUserId());List<SimpleGrantedAuthority> authorityList = userRoleVOList.stream().map(userRoleVO -> new SimpleGrantedAuthority("ROLE_" + userRoleVO.getRoleName())).collect(Collectors.toList());return new WxAppletAuthenticationToken(user.getOpenId(), user.getUserId(), authorityList);}
}

4. JWTFilter

在AuthenticationProcessingFilter之前,先验证客户端的token

@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Resourceprivate UserService userService;@Resourceprivate UserRoleService userRoleService;@Overrideprotected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {String token = httpServletRequest.getHeader("Authorization");if (!ObjectUtil.isEmpty(token)) {// 从token中获取openId和userIdString openId = (String) JwtUtils.getClaim(token, "openId");Long userId = (Long) JwtUtils.getClaim(token, "userId");if (!ObjectUtil.isEmpty(userId) && !ObjectUtil.isEmpty(openId) && SecurityContextHolder.getContext().getAuthentication() == null) {log.info("获取" + userId + "的角色");List<UserRoleVO> userRoleVOList = userRoleService.getByUserId(userId);List<SimpleGrantedAuthority> authorityList = userRoleVOList.stream().map(userRoleVO -> new SimpleGrantedAuthority("ROLE_" + userRoleVO.getRoleName())).collect(Collectors.toList());// 将token加入安全上下文SecurityContextHolder.getContext().setAuthentication(new WxAppletAuthenticationToken(openId, userId, authorityList));}}filterChain.doFilter(httpServletRequest, httpServletResponse);}
}

5. AuthenticationEntryPoint

未登录时是处理端点

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {httpServletRequest.getRequestDispatcher("/error/auth").forward(httpServletRequest, httpServletResponse);}
}

6. AuthenticationSuccessHandler

登陆成功后的处理器

public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {WxAppletAuthenticationToken authenticationToken = (WxAppletAuthenticationToken) authentication;Map<String, Object> data = new HashMap<>();data.put("userId", authenticationToken.getUserId());data.put("openId", authenticationToken.getOpenId());// 写回tokenString token = JwtUtils.getToken(data);httpServletResponse.setContentType(ContentType.JSON.getValue());httpServletResponse.setCharacterEncoding("UTF-8");httpServletResponse.getWriter().write(JSONUtil.parseObj(new LoginVO(token)).toStringPretty());}
}

7. 全局异常捕获

@RestControllerAdvice
@Order(1)
public class GlobalExceptionHandler {/*** 禁止访问*/@ExceptionHandler(AccessDeniedException.class)public Result accessDeniedException() {return Result.error(ResultCode.NO_PERMISSION);}
}

8. WebSecurityConfig

Spring Security配置

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().sessionManagement()// 不创建Session, 使用jwt来管理用户的登录状态.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers("/error/**", "/swagger-ui.html/**", "/webjars/**", "/v2/**", "/swagger-resources/**").permitAll().anyRequest().authenticated().and().exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint());http.addFilterAt(getWxAppletAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class).addFilterBefore(getJwtAuthenticationTokenFilter(), WxAppletAuthenticationFilter.class);;}@Resourceprivate WxAppletAuthenticationManager wxAppletAuthenticationManager;@Beanpublic WxAppletAuthenticationFilter getWxAppletAuthenticationFilter() {WxAppletAuthenticationFilter wxAppletAuthenticationFilter = new WxAppletAuthenticationFilter("/login");wxAppletAuthenticationFilter.setAuthenticationManager(wxAppletAuthenticationManager);wxAppletAuthenticationFilter.setAuthenticationSuccessHandler(getCustomAuthenticationSuccessHandler());return wxAppletAuthenticationFilter;}@Beanpublic CustomAuthenticationSuccessHandler getCustomAuthenticationSuccessHandler() {return new CustomAuthenticationSuccessHandler();}@Beanpublic JwtAuthenticationTokenFilter getJwtAuthenticationTokenFilter() {return new JwtAuthenticationTokenFilter();}
}

9. 开启全局方法安全

@Bean
public CustomAuthenticationSuccessHandler getCustomAuthenticationSuccessHandler() {
return new CustomAuthenticationSuccessHandler();
}

@Bean
public JwtAuthenticationTokenFilter getJwtAuthenticationTokenFilter() {return new JwtAuthenticationTokenFilter();
}

}


## 9. 开启全局方法安全> 在启动类上加上注解@EnableGlobalMethodSecurity(prePostEnabled = true)

Spring Boot + Spring Security + JWT + 微信小程序登录相关推荐

  1. spring boot开发QQ音乐微信小程序(包含服务端源码)

    spring boot+spring mvc+spring整合开发QQ音乐微信小程序(含简单服务端) 项目描述: spring boot+spring mvc+spring代理请求QQ音乐接口获取数据 ...

  2. Spring Boot后端+Vue前端+微信小程序,完整的开源解决方案!

    项目简介 一个小商场系统,包括: 后端:Spring Boot 管理员前端:Vue 用户前端:微信小程序 功能介绍 1.小商城 首页 专题列表.专题详情 分类列表.分类详情 品牌列表.品牌详情 新品首 ...

  3. 基于Spring Boot的点餐微信小程序设计与实现

    摘 要 近年来,国民收入的提高各个行业都得到了长足发展,其中也带动着互联网行业飞速发展,许多传统行业开始与互联网结合并通过数字化的改造.转型与升级创造出新的发展生态.尤其在国人最关注的"吃& ...

  4. java版微信小程序登录商城源码Spring Cloud+Spring Boot+mybatis+security+uniapp+Redis+MQ+VR全景+b2b2c多商家入驻前后端分离商城源码

    @源码地址来源: https://minglisoft.cn/honghu2/business.html 微信小程序登录代码: /*** Copyright © 2012-2017 <a hre ...

  5. Spring Security oauth2.0微信小程序登录

    微信小程序前期开发准备,可以参考这篇文章微信小程序前期准备 1.学习过Spring Secrity oauth2.0的都知道,他有四种登录模式可以选择 authorization code(授权码模式 ...

  6. 用Spring Boot完成微信小程序登录

    使用Spring Boot完成微信小程序登录 由于微信最近的版本更新,wx.getUserInfo()的这个接口即将失效,将用wx.getUserProfile()替换,所以近期我也对自己的登录进行更 ...

  7. Spring Boot + 微信小程序——登录凭证校验DEMO

    基本概念 微信小程序-登录凭证校验:通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程. 微信小程序API https://developers.weix ...

  8. java版微信小程序登录商城源码Spring Cloud+Redis+MQ+VR全景+b2b2c多商家入驻前后端分离商城源码

    @源码地址来源: https://minglisoft.cn/honghu2/business.html 微信小程序登录代码: /*** Copyright © 2012-2017 <a hre ...

  9. 微信小程序python token验证_微信小程序登录对接Django后端实现JWT方式验证登录

    点击授权按钮后可以显示部分资料和头像,点击修改资料可以修改部分资料. 1.使用微信小程序登录和获取用户信息Api接口 2.把Api获取的用户资料和code发送给django后端 3.通过微信接口把co ...

最新文章

  1. mySQL 教程 第16章 MySQL复制
  2. java mqtt 断开连接,可以将MQTT Paho客户端断开连接吗?
  3. 兑吧:游戏化玩转用户运营的三驾马车
  4. hashmap java_Java – HashMap详细说明
  5. Java获取硬盘信息
  6. python根据相关系数绘制热力图
  7. 定期存款转消费卡项目需求书
  8. Linux下 文件或文件夹的复制(拷贝 cp)
  9. 姿态角解算(MPU6050 加速度计加陀螺仪)
  10. c语言公开课教案,9、祝福优质课一等奖教案
  11. R代码模拟世界杯1000次,速成2018世界杯预言帝
  12. java写一个android程序_【Android开发笔记】3.编写第一个Android程序
  13. 朋友圈宣传文案 朋友圈产品推广文案模板怎么写?
  14. pygame 游戏开发
  15. 信创操作系统--统信UOS桌面版(使用终端:bash、tty、基本shell操作)
  16. 关于InnoDB存储引擎 text blob 大字段的存储和优化--转载
  17. [Python从零到壹] 三十三.图像处理基础篇之什么是图像处理和OpenCV配置
  18. WordCount单词计数详解
  19. 还原一个真实的马斯克:太空殖民时代的钢铁侠
  20. Opencv 3入门(毛星云)摘要

热门文章

  1. es多个字段排序_如何解决 ES 复杂聚合排序问题(嵌套桶排序)?
  2. 手游自动化测试基础:方法及流程
  3. 最左前缀 mysql优化器_mysql查询优化之索引类型、最左前缀
  4. python注释可用于表明作者和版权信息_Python-注释帮助我们理解-No9
  5. python黑魔法指南_Python黑魔法大全
  6. ApkScan-PKID查壳工具+脱壳(搬运)
  7. Web浏览过程中涉及到的协议
  8. Android Studio 连接阿里云数据库【制作基于数据库的多人远程聊天APP】
  9. 重装也无法修复此计算机,无法重装系统解决方法
  10. windows查看本机的mac地址