SpringCloud 大型系列课程正在制作中,欢迎大家关注与提意见。
程序员每天的CV 与 板砖,也要知其所以然,本系列课程可以帮助初学者学习 SpringBooot 项目开发 与 SpringCloud 微服务系列项目开发

1 项目准备

创建SpringBoot基础项目
SpringBoot项目集成mybatis
SpringBoot 集成 Druid 数据源【SpringBoot系列3】
SpringBoot MyBatis 实现分页查询数据【SpringBoot系列4】
SpringBoot MyBatis-Plus 集成 【SpringBoot系列5】
SpringBoot mybatis-plus-generator 代码生成器 【SpringBoot系列6】
SpringBoot MyBatis-Plus 分页查询 【SpringBoot系列7】
SpringBoot 集成Redis缓存 以及实现基本的数据缓存【SpringBoot系列8】

Spring Security(官网在这里) 是 Spring 社区的一个顶级项目,也是 Spring Boot 官方推荐使用的安全框架。

本文章实现的是SpringBoot整合Spring Security实现认证校验功能,实现方式有多种,本文章只是其中一种,如有不足,欢迎留言。


首先在pom.xml 添加依赖如下:

 <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.25</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.5</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId><version>3.0.4</version></dependency>

JWT(JSON Web Token) 用来生成 Token ,JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名.

添加依赖后,启动项目,在浏览器中访问任何一个接口都会出现 登录认证

1 jjwt 生成 token 工具

这里就是根据 用户的 username + 密钥来生成token ,然后解密 token 等等,在 Spring Security 认证过程中使用。

import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;import javax.crypto.SecretKey;
import java.util.Date;@Component
@Slf4j
public class JWTGenerator {//密钥private static String sign ="cuAihCz53DZRjZwbsGcZJ2Ai6At+T142uphtJMsk7iQ=";//生成tokenpublic String generateToken(Authentication authentication) {//用户的核心标识String username = authentication.getName();// 过期时间 - 30分钟Date expireDate = new Date(System.currentTimeMillis() + 30 * 60 * 1000);String token = Jwts.builder().setSubject(username).setIssuedAt(new Date()).setExpiration(expireDate).signWith(generalKeyByDecoders())  //设置token加密方式和密.compact();return token;}public static SecretKey generalKeyByDecoders() {return Keys.hmacShaKeyFor(Decoders.BASE64.decode(sign));}/*** 解密token* @param token* @return*/public String getUsernameFromJWT(String token) {JwtParserBuilder builder = Jwts.parserBuilder();Jws<Claims> claimsJws = builder.setSigningKey(generalKeyByDecoders()).build().parseClaimsJws(token);return claimsJws.getBody().getSubject();}/*** 校验token* @param token* @return*/public boolean validateToken(String token) {log.error("验证 token  {}", token);try {JwtParserBuilder builder = Jwts.parserBuilder();Jws<Claims> claimsJws = builder.setSigningKey(generalKeyByDecoders()).build().parseClaimsJws(token);return true;} catch (ExpiredJwtException e) {Claims claims = e.getClaims();// 检查tokenthrow new BadCredentialsException("TOKEN已过期,请重新登录!");} catch (AuthenticationException e) {throw new AuthenticationCredentialsNotFoundException("JWT was expired or incorrect");} catch (Exception ex) {log.error("token认证失败 {}", ex.getMessage());throw new AuthenticationCredentialsNotFoundException("JWT was expired or incorrect");}}
}

2 登录认证 Controller 定义

@Slf4j
@RestController
@RequestMapping("/api/auth")
public class AuthController {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate JWTGenerator jwtGenerator;@PostMapping("login")public R login(@RequestBody LoginRequest loginDto){log.info("登录认证开始 {}",loginDto.toString());Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginDto.getUserName(),loginDto.getPassword()));// 认证成功存储认证信息到上下文SecurityContextHolder.getContext().setAuthentication(authentication);log.info("登录认证完成 {}",loginDto.toString());String token = jwtGenerator.generateToken(authentication);log.info("登录认证生成 token {}",token);return R.okData(token);}}
  • JWTGenerator 第一步中定义的 token 生成工具,在登录校验完成时,生成token.

  • AuthenticationManager 只关注认证成功与否而并不关心具体的认证方式,如果验证成功,则返回完全填充的Authentication对象(包括授予的权限)。

import lombok.Data;
import lombok.ToString;import java.io.Serializable;
@Data
@ToString
public class LoginRequest implements Serializable {private String userName ;private String password;
}

3 核心配置 SecurityConfig

SecurityConfig 用来配置 Spring Security 的拦截策略以及认证策略等等

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
@EnableWebSecurity
public class SecurityConfig {//自定义异常认证处理private JwtAuthEntryPoint authEntryPoint;//自定义授权异常处理private MyAccessDeniedHandler myAccessDeniedHandler;@Autowiredpublic SecurityConfig(JwtAuthEntryPoint authEntryPoint, MyAccessDeniedHandler myAccessDeniedHandler) {this.authEntryPoint = authEntryPoint;this.myAccessDeniedHandler = myAccessDeniedHandler;}@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.csrf().disable().exceptionHandling().accessDeniedHandler(myAccessDeniedHandler).authenticationEntryPoint(authEntryPoint).and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()//放行静态资源文件夹(路径要具体情况具体分析).antMatchers("/api/auth/**","/css/**", "/js/**", "/image/**","/app/**","/swagger/**","/swagger-ui.html","/app/**","/swagger-resources/**","/v2/**","/webjars/**").permitAll().anyRequest().authenticated().and().httpBasic();http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);return http.build();}@Beanpublic AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {return authenticationConfiguration.getAuthenticationManager();}@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}// 自定义 认证过滤器@Beanpublic JWTAuthenticationFilter jwtAuthenticationFilter() {return new JWTAuthenticationFilter();}
}
3.1 JwtAuthEntryPoint 自定义的认证失败的回调处理
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;@Component
@Slf4j
public class JwtAuthEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {String message = authException.getMessage();log.error("token 拦截 {}",message);response.setCharacterEncoding("utf-8");response.setContentType("text/javascript;charset=utf-8");Map<String,Object> map = new HashMap<>();map.put("code",403);map.put("message","您未登录,没有访问权限");response.getWriter().print(JSONObject.toJSONString(map));}
}
3.2 MyAccessDeniedHandler 自定义的授权失败的回调处理
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 授权异常*/
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException, IOException {response.setStatus(403);response.getWriter().write("Forbidden:" + accessDeniedException.getMessage());}
}

4 核心过滤器 JWTAuthenticationFilter

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class JWTAuthenticationFilter extends OncePerRequestFilter {@Autowiredprivate JWTGenerator tokenGenerator;@Autowiredprivate CustomUserDetailsService customUserDetailsService;@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {//获取请求头中的 token 信息String token = getJWTFromRequest(request);//校验tokenif(StringUtils.hasText(token) && tokenGenerator.validateToken(token)) {//解析 token 中的用户信息 (用户的唯一标识 )String username = tokenGenerator.getUsernameFromJWT(token);UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null,userDetails.getAuthorities());authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authenticationToken);}filterChain.doFilter(request, response);}/*** 就是校验请求头的一种格式 可以随便定义* 只要可以解析 就可以* @param request* @return*/private String getJWTFromRequest(HttpServletRequest request) {String bearerToken = request.getHeader("Authorization");if(StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {return bearerToken.substring(7, bearerToken.length());}return null;}

5 CustomUserDetailsService 用户校验实现

@Service
public class CustomUserDetailsService  implements UserDetailsService {private UserService userService;@Autowiredpublic CustomUserDetailsService(UserService userService) {this.userService = userService;}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {UserInfo user = userService.getByUsername(username);if(user==null){throw new  UsernameNotFoundException("Username not found");}User user1 = new User(user.getUserName(), user.getPassword(), mapRolesToAuthorities(user.getRoles()));return user1;}private Collection<GrantedAuthority> mapRolesToAuthorities(List<Role> roles) {return roles.stream().map(role -> new SimpleGrantedAuthority(role.getName())).collect(Collectors.toList());}
}

这里使用到的 UserService 就是项目中查询用户信息的服务。
然后使用 postman 来访问接口

然后调用 登录接口生成 token


然后在访问其他接口里放入请求头信息

项目源码在这里 :https://gitee.com/android.long/spring-boot-study/tree/master/biglead-api-07-security
有兴趣可以关注一下公众号:biglead

SpringBoot 整合 Spring Security 实现安全认证【SpringBoot系列9】相关推荐

  1. 八、springboot整合Spring Security

    springboot整合Spring Security 简介 Spring Security是一个功能强大且可高度自定义的身份验证和访问控制框架.它是保护基于Spring的应用程序的事实标准. Spr ...

  2. springBoot整合spring security+JWT实现单点登录与权限管理前后端分离

    在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与权限管理. ...

  3. springBoot整合spring security+JWT实现单点登录与权限管理前后端分离--筑基中期

    写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...

  4. SpringBoot整合Spring Security【超详细教程】

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/Lee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 Spring Security是一个 ...

  5. SpringBoot 整合Spring Security(简单版)

    1 写在前面 关于spring security的介绍,网上一大堆,这里就不介绍了,这里直接使用springboot开始整合 2 整个流程 spring security授权和认证的流程大致和shir ...

  6. SpringBoot整合Spring Security——登录管理

    文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandle 1.2 CustomAuthenticationFailureHandler 1.3 ...

  7. SpringBoot整合Spring Security

    个人资源与分享网站:http://xiaocaoshare.com/ SpringSecurity核心功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) 1.pom.xml < ...

  8. SpringBoot整合Spring Security——第三章异常处理

    文章目录 一.常见异常 二.源码分析 三.处理异常 四.拓展spring security authenticationProvider用法及关闭不隐藏UserNotFoundException的解决 ...

  9. 31 | SpringBoot安全之整合Spring Security

    一.安全 应用程序的两个主要区域是"认证"和"授权"(或者访问控制),这两个主要区域是安全的两个目标. 身份验证意味着确认您自己的身份,而授权意味着授予对系统的 ...

最新文章

  1. 网络营销期间交换链接多会有更多网络营销的机会吗?
  2. 电脑动态屏保_8款电脑软件,每一款都能让你的电脑更好用
  3. C语言可变参数只会用算啥本事?看我来抽丝剥茧干翻它!
  4. android okgo参数,Android OkGo基本操作
  5. WEB OS + WEB IM(续)
  6. Spring学习总结(14)——Spring10种常见异常解决方法
  7. 在eclispe的类中快速打出main方法
  8. java获取窗口_获取窗口句柄
  9. BP神经网络学习总结
  10. Linux常用软件包(常用命令)
  11. yolov3 原理代码复现2
  12. 用 Python 挪车、管理农场,这届 PyCon 有点香
  13. 树莓派-内核启动报错mmc0: error -5 whilst initialising MMC card
  14. MySQL三 插入语句包含查询语句
  15. clear 方法的解释及用法
  16. 机电一体化T6113电气控制系统的设计(论文+DWG图纸)
  17. 量子计算机芯片的制造过程,全干货!一文读懂芯片制造及量子芯片!
  18. 软件开发相关的读书笔记 问题与方法
  19. WRF4.3和WPS的编译和安装
  20. 学校排课老师的福音:短短几分钟轻松完成学校排课任务

热门文章

  1. 视觉AI保驾护航——视频直播
  2. 张天钰 内大计算机学院,计算机学院学风建设情况通报
  3. 戴尔: 这一次都用了什么技术突破创新?
  4. Java、JSP等城市交通查询系统的设计
  5. UBTC——区块链下一个领航大旗
  6. 【CTF】考核比赛知识准备WEB部分(一)php和mysql
  7. 浪潮8路服务器型号,浪潮推出自主设计8路服务器
  8. 01、Java基础知识
  9. DTK 每日自动更新其 API 文档
  10. adb interface找不到驱动程序Android Studio (学习记录)