SpringSecurity笔记2

news/2024/10/17 22:12:39/

配置类:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {// 已登录的用户的token验证@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;// 登录失败@Autowiredprivate AuthenticationEntryPointImpl authenticationEntryPoint;// 认证失败@Autowiredprivate AccessDeniedHandlerImpl accessDeniedHandler;// 前端用户登录的用户信息验证@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}// 密码加密解密@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {// super.configure(http);http// 关闭csrf.csrf().disable()// 不通过session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 放行.antMatchers("/login").anonymous()// 这个接口需要认证才能访问.antMatchers("/link/getAllLink").authenticated().antMatchers("/logout").authenticated()// 其余的接口也放行.anyRequest().permitAll();// 关闭security的默认关闭接口http.logout().disable();// 配置过滤器http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);// 配置异常处理器http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler);// 允许跨域http.cors();}
}

用户登录流程:

@Service
public class BlogLoginServiceImpl implements BlogLoginService {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate RedisTemplate<Object, Object> redisTemplate;@Overridepublic ResponseResult login(User user) {// 放入用户名和密码UsernamePasswordAuthenticationToken authentication =new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());// authenticate 会调用 UserDetailsServiceImpl 登录判断Authentication authenticate = authenticationManager.authenticate(authentication);// 判断是否认证通过if (authenticate == null) throw new RuntimeException("用户名或密码错误");// 获取userId 生成tokenLoginUser loginUser = (LoginUser) authenticate.getPrincipal();Long userId = loginUser.getUser().getId();String token = JwtUtil.createJWT(String.valueOf(userId));// 用户信息存入redisredisTemplate.opsForValue().set("bloglogin:" + userId, loginUser,1, TimeUnit.DAYS);// token和userinfo封装 返回BlogUserLoginVo vo = new BlogUserLoginVo();vo.setToken(token);vo.setUserInfo(BeanCopyUtils.copyBean(loginUser.getUser(), UserInfoVo.class));return ResponseResult.success(vo);}
}
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;// 登录判断@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {if (StringUtils.isEmpty(username)) throw new RuntimeException("用户名不能为空");// 条件LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getUserName, username);// 查询User user = userMapper.selectOne(wrapper);if (user == null) throw new RuntimeException("用户不存在");return new LoginUser(user);}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginUser implements UserDetails {private User user;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {// 权限集合return null;}@Overridepublic String getPassword() {return user.getPassword();}@Overridepublic String getUsername() {return user.getUserName();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}

用户登陆后,访问权限接口,token认证拦截器:

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {// 用户访问需要登录的接口,验证token@Autowiredprivate ObjectMapper om;@Autowiredprivate RedisTemplate redisTemplate;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 获取tokenString token = request.getHeader("token");if (!StringUtils.hasText(token)) {// 后面登录的security还会进行校验filterChain.doFilter(request, response);return;}// 解析token 获取userIdClaims claims = null;try {claims = JwtUtil.parseJWT(token);} catch (Exception e) {e.printStackTrace();// 过期// 非法token// 响应前端重新登录ResponseResult result = new ResponseResult(401, "用户未登录", null);WebUtils.renderString(response, om.writeValueAsString(result));return;}String userId = claims.getSubject();// 从redis中获取用户信息LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get("bloglogin:" + userId);if (loginUser == null) {// redis里没有ResponseResult result = new ResponseResult(402, "登录已过期", null);WebUtils.renderString(response, om.writeValueAsString(result));return;}// 存入SecurityContextHolder// 未认证的是2个参数,已认证的是3个参数UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginUser, null, null);SecurityContextHolder.getContext().setAuthentication(authentication);// 放行filterChain.doFilter(request, response);return;}
}

以上完成后,拦截后不会返回前端json结果

自定义认证失败处理:

@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {@Autowiredprivate ObjectMapper om;@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {// 登录失败失败响应给前端authException.printStackTrace();// BadCredentialsException 用户名或密码错误// InsufficientAuthenticationException 需要登录ResponseResult result = null;if (authException instanceof BadCredentialsException)result = new ResponseResult(401, authException.getMessage(), null);else if (authException instanceof InsufficientAuthenticationException)result = new ResponseResult(402, "用户未登录", null);elseresult = new ResponseResult(403, authException.getMessage(), null);WebUtils.renderString(response, om.writeValueAsString(result));}
}

 下面这个是鉴权的响应,目前还用不到:

@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {@Autowiredprivate ObjectMapper om;@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {// 鉴权失败的响应accessDeniedException.printStackTrace();ResponseResult result = new ResponseResult(401, "无权限操作", null);WebUtils.renderString(response, om.writeValueAsString(result));}
}

统一异常处理:

@Data
@NoArgsConstructor
public class SystemException extends RuntimeException {private Integer code;private String msg;public SystemException(Integer code, String msg) {super(msg);this.code = code;this.msg = msg;}
}

// 捕获Controller的异常
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {// 可控的异常@ExceptionHandler(SystemException.class)public ResponseResult SystemExceptionHandler(SystemException e) {// 打印日志log.error("出现了异常! {}", e);// 响应前端return new ResponseResult(e.getCode(), e.getMsg(), null);}// 不可控的异常@ExceptionHandler(Exception.class)public ResponseResult exceptionHandler(Exception e) {// 打印日志log.error("出现了异常! {}", e);// 响应前端return new ResponseResult(500, e.getMessage(), null);}
}

参考视频:

B站最通俗易懂手把手SpringBoot+Vue项目实战-前后端分离博客项目-Java项目_哔哩哔哩_bilibili


http://www.ppmy.cn/news/687185.html

相关文章

IE浏览器跳转无效的问题

IE11浏览器下"window.location.href "[页面]"不生效的问题 参考链接&#xff1a;https://www.cnblogs.com/zhourongcode/p/9341529.html 参考链接&#xff1a;https://blog.csdn.net/moshuchao/article/details/51553354 window.location.href “./popup.jsp…

Delphi用IE浏览器打开网址链接的三种

简单点可以用默认浏览器打开&#xff0c;方法如下&#xff1a; uses shellapi procedure TForm1.Button2Click(Sender: TObject); begin ShellExecut(Application.Handle, nil, http://iisnine.lofter.com, nil, nil, SW_SHOWNORMAL); end; IE打开网址链接的方法第一种&a…

关于前端页面在IE浏览器下无法显示的问题

由于框架的发展和技术的革新&#xff0c;很多语言必须兼容浏览器才能很好的显示出新的特性和样式&#xff0c;那么我们的前端页面如果在IE浏览器下无法显示时该用什么办法提示用户(提示用户升级浏览器)??? 最实用的办法就是加上判断浏览器是不是IE浏览器的语法&#xff1a; …

关于Chrome浏览器调用IE浏览器

最近遇到一个问题我们想要谷歌浏览器和IE 浏览器兼容 因为有一些产品只支持IE 而我们使用的是谷歌浏览器&#xff0c;所以出现了这么一个问题 在网上找了几天的内容发现都是谷歌4.5版本以下去下载一个IE Tab插件去解决的 但我们使用的是谷歌75最新版本的&#xff0c;安装不上这…

ie退出全屏快捷键_IE浏览器快捷键使用说明 ie浏览器快捷键大全

当我们在使用IE浏览器时&#xff0c;熟练的使用快捷键的能让我们的工作效率大幅度提高&#xff0c;可以使我们上网变的更加流畅方便&#xff0c;下面小编就来给大家科普一下ie浏览器都有那些快捷键&#xff0c;这些快捷键又都有什么作用吧。 一般快捷键 F11打开/关闭全屏模式 T…

springboot校园点餐小程序

校园点餐系统 springboot校园点餐系统小程序 java校园点餐小程序 技术&#xff1a; 基于springbootvue小程序校园点餐系统的设计与实现 运行环境&#xff1a; JAVA版本&#xff1a;JDK1.8 IDE类型&#xff1a;IDEA、Eclipse都可运行 数据库类型&#xff1a;MySql&#xff08;…

Excel VBA打开IE浏览器的网页

目的&#xff1a;使用 Excel VBA 进行网页抓取&#xff08;web scraping&#xff09; 1. 运行IE的前设置&#xff08;setting&#xff09; 2.输入代码进行IE调取&#xff08;Navigate&#xff09; 3.操作IE打开WEB页面 1. 运行IE的前设置&#xff08;setting&#xff09; …

Python爬虫入门4:使用IE浏览器获取网站访问的http信息

☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython ░ 一、引言 在《https://blog.csdn.net/LaoYuanPython/article/details/113055084 Python爬虫入门3:使用google浏览器获取网站访问的http信息》中介绍了使用Google浏览器怎么获取网站访问的http相关报文信息…