SpringSecurity深度解析与实践(3)

这里写自定义目录标题

  • 引言
  • SpringSecurity之授权
    • 授权介绍
    • java权限集成
  • 登录失败三次用户上锁

在这里插入图片描述

引言

SpringSecurity深度解析与实践(2)的网址

SpringSecurity之授权

授权介绍

Spring Security 中的授权分为两种类型:

  • 基于角色的授权:以用户所属角色为基础进行授权,如管理员、普通用户等,通过为用户分配角色来控制其对资源的访问权限。
  • 基于资源的授权:以资源为基础进行授权,如 URL、方法等,通过定义资源所需的权限,来控制对该资源的访问权限。

Spring Security 提供了多种实现授权的机制,最常用的是使用基于注解的方式,建立起访问资源和权限之间的映射关系。

其中最常用的两个注解是 @Secured@PreAuthorize@Secured 注解是更早的注解,基于角色的授权比较适用,@PreAuthorize 基于 SpEL 表达式的方式,可灵活定义所需的权限,通常用于基于资源的授权。

java权限集成

WebSecurityConfig配置类

package com.yuan.springsecurity1.config;import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuan.springsecurity1.resp.JsonResponseBody;
import com.yuan.springsecurity1.resp.JsonResponseStatus;
import com.yuan.springsecurity1.service.impl.UserServiceImpl;
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.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;import javax.sql.DataSource;@Configuration
//开启SpringSecurity的默认行为
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Autowiredprivate DataSource dataSource;/*** 配置持久化Token方式,注意tokenRepository.setCreateTableOnStartup()配置*/@Beanpublic PersistentTokenRepository persistentTokenRepository(){JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();tokenRepository.setDataSource(dataSource);// 设置为true要保障数据库该表不存在,不然会报异常哦// 所以第二次打开服务器应用程序的时候得把它设为falsetokenRepository.setCreateTableOnStartup(false);return tokenRepository;}@Autowiredprivate MyUserDetailsService myUserDetailsService;@AutowiredObjectMapper objectMapper;@AutowiredMyAuthenticationFailureHandler myAuthenticationFailureHandler;/*** 获取AuthenticationManager(认证管理器),登录时认证使用(基于数据库方式)* @param* @return* @throws Exception*/@Beanpublic AuthenticationManager authenticationManager() throws Exception {//创建DaoAuthenticationProviderDaoAuthenticationProvider provider=new DaoAuthenticationProvider();//设置userDetailsService,基于数据库方式进行身份认证provider.setUserDetailsService(myUserDetailsService);//配置密码编码器provider.setPasswordEncoder(passwordEncoder());return new ProviderManager(provider);}@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http)throws Exception{http.authorizeRequests()// 开放接口访问权限,不需要登录就可以访问.antMatchers("/toLogin").permitAll()//访问路径有admin的方法时,需要有ADMIN的身份
//                    .antMatchers("/admin/**").hasRole("ADMIN")
//                    .antMatchers("/user/**").hasAnyRole("ADMIN","USER")// 其余所有请求全部需要鉴权认证.anyRequest().authenticated().and().formLogin()// 设置登录页面的 URL.loginPage("/toLogin")// 设置登录请求的 URL,即表单提交的 URL.loginProcessingUrl("/userLogin")// 设置登录表单中用户名字段的参数名,默认为username.usernameParameter("username")// 设置登录表单中密码字段的参数名,默认为password.passwordParameter("password")//成功后的处理.successHandler((req,resp,auth)->{
//                    resp.sendRedirect("/index");Object user = auth.getPrincipal();objectMapper.writeValue(resp.getOutputStream(), JsonResponseBody.success(user));})//登录失败的处理.failureHandler(myAuthenticationFailureHandler).and().exceptionHandling()
//                .accessDeniedPage("/noAccess")//权限不够处理.accessDeniedHandler((req,resp,ex)->{objectMapper.writeValue(resp.getOutputStream(),JsonResponseBody.other(JsonResponseStatus.NO_ACCESS));})//没有认证(登录)处理.authenticationEntryPoint((req,resp,ex)->{objectMapper.writeValue(resp.getOutputStream(),JsonResponseBody.other(JsonResponseStatus.NO_LOGIN));}).and().logout()// 设置安全退出的URL路径.logoutUrl("/logout")// 设置退出成功后跳转的路径.logoutSuccessUrl("/toLogin").and().rememberMe()// 指定 rememberMe 的参数名,用于在表单中携带 rememberMe 的值。.rememberMeParameter("remember-me")// 指定 rememberMe 的有效期,单位为秒,默认2周。.tokenValiditySeconds(600)// 指定 rememberMe 的 cookie 名称。.rememberMeCookieName("remember-me-cookie")// 指定 rememberMe 的 token 存储方式,可以使用默认的 PersistentTokenRepository 或自定义的实现。.tokenRepository(persistentTokenRepository())// 指定 rememberMe 的认证方式,需要实现 UserDetailsService 接口,并在其中查询用户信息。.userDetailsService(myUserDetailsService);
//        http.csrf().disable();return http.build();}
}

登录权限绑定

package com.yuan.springsecurity1.config;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.yuan.springsecurity1.pojo.*;
import com.yuan.springsecurity1.mapper.UserMapper;
import com.yuan.springsecurity1.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.Component;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;/*** <p>* 用户信息表 服务实现类* </p>** @author yuan* @since 2023-12-21*/
@Component
public class MyUserDetailsService implements  UserDetailsService {@Autowiredprivate IUserService iUserService;@Autowiredprivate IUserRoleService iUserRoleService;@Autowiredprivate IRoleService iRoleService;@Autowiredprivate IRoleModuleService iRoleModuleService;@Autowiredprivate IModuleService iModuleService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = iUserService.getOne(new QueryWrapper<User>().eq("username", username));if(user==null)throw new UsernameNotFoundException("用户名无效");//查询所有的身份,map 遍历数据对象,返回的数据放到一个新的流中,collect(Collectors.toList())用list集合接收List<Integer> userIds = iUserRoleService.list(new QueryWrapper<UserRole>().eq("user_id", user.getId())).stream().map(UserRole::getRoleId).collect(Collectors.toList());//根据role_id拿到身份名称集合List<String> roleNames = iRoleService.list(new QueryWrapper<Role>().in("role_id", userIds)).stream().map(Role::getRoleName).collect(Collectors.toList());//根据身份id role_id拿到权限id module_idList<Integer> moduleIds = iRoleModuleService.list(new QueryWrapper<RoleModule>().in("role_id", userIds)).stream().map(RoleModule::getModuleId).collect(Collectors.toList());//根据权限id拿到对应的urlList<String> urls = iModuleService.list(new QueryWrapper<Module>().in("id", moduleIds)).stream().map(Module::getUrl).filter(Objects::nonNull).collect(Collectors.toList());roleNames.addAll(urls);List<SimpleGrantedAuthority> authorities = roleNames.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());user.setAuthorities(authorities);return user;}
}

Controller类数据

    @ResponseBody@RequestMapping("/o_f")@PreAuthorize("hasAnyAuthority('order:manager:analysis')")public String o_f() {return "订单分析";}@ResponseBody@RequestMapping("/b_add")@PreAuthorize("hasAnyAuthority('book:manager:add')")public String b_add() {return "书籍新增";}

需要添加一个规则,判断是否有权限,我这个放在WebSecurityConfig类上

@EnableGlobalMethodSecurity(prePostEnabled = true)

登录失败三次用户上锁

搭配WebSecurityConfig类中失败的对象

package com.yuan.springsecurity1.config;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuan.springsecurity1.pojo.User;
import com.yuan.springsecurity1.resp.JsonResponseBody;
import com.yuan.springsecurity1.resp.JsonResponseStatus;
import com.yuan.springsecurity1.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author 叶秋* @site* @company 卓京公司* @create 2023-12-23 23:21*/
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {@AutowiredObjectMapper objectMapper;@Autowiredprivate IUserService iUserService;@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {if(1==2){ //假设超过三次失败User user = iUserService.getOne(new QueryWrapper<User>().eq("username", request.getParameter("username")));user.setAccountNonLocked(false);iUserService.updateById(user);}objectMapper.writeValue(response.getOutputStream(), JsonResponseBody.other(JsonResponseStatus.LOGIN_FAILURE));}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/454303.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单解释什么是 依赖注入 和 控制反转

简单解释什么是 依赖注入 和 控制反转2017-07-09 关于 依赖注入 与 控制反转 的概念有些人觉得很难理解&#xff0c;最近在给别人讲这个概念的时候梳理了一个比较好理解的解释&#xff0c;而且我认为非技术人员也应该能听的懂&#xff0c;因此分享给大家&#xff0c;希望下次你…

python pip install指定国内源镜像

有时候安装一些依赖包&#xff0c;网不好&#xff0c;直接超时&#xff0c;或者这个包就是死都下不下来的时候&#xff0c;可以指定国内源镜像。 pip install -i 国内镜像地址 包名 清华&#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple 阿里云&#xff1a;http://mirr…

机器学习之单标签多分类及多标签多分类

单标签二分类算法 Logistic算法 单标签多分类算法 Softmax算法 One-Versus-One&#xff08;ovo&#xff09;&#xff1a;一对一 One-Versus-All / One-Versus-the-Rest&#xff08;ova/ovr&#xff09;&#xff1a; 一对多 ovo和ovr的区别 Error Correcting Output code…

ionic3 隐藏子页面tabs

看了几天ionic3 问题还挺多的&#xff0c;今天想把所有子页面tabs 给去掉&#xff0c;整了半天&#xff0c;发现app.Module 是可以配置的 修改 IonicModule.forRoot(MyApp&#xff09; imports: [BrowserModule,// IonicModule.forRoot(MyApp),HttpModule,IonicModule.forRoot(…

cas单点登录-jdbc认证(三)

前言 本节的内容为JDBC认证&#xff0c;查找数据库进行验证&#xff0c;其中包括&#xff1a; 密码加密策略&#xff08;无密码&#xff0c;简单加密&#xff0c;加盐处理&#xff09;认证策略&#xff08;jdbc&#xff09;一、业务需求 不同的公司&#xff0c;需求业务需求或者…

get clone 出现 fatal: the remote end hung up unexpectedly5 MiB | 892.00 KiB/s 报错信息

fatal: the remote end hung up unexpectedly5 MiB | 892.00 KiB/s 解决方案 &#xff08;亲测有效&#xff09; 解决方案如下&#xff1a; git clone时加上 --depth1&#xff0c;比如&#xff1a; git clone https://gitee.com/songyitian/tctm.git --depth 1depth用于指定…

mybatis foreach map_重学Mybatis(六)-------输入映射(含面试题)

博主将会针对Java面试题写一组文章&#xff0c;包括J2ee&#xff0c;SQL&#xff0c;主流Web框架&#xff0c;中间件等面试过程中面试官经常问的问题&#xff0c;欢迎大家关注。一起学习&#xff0c;一起成长&#xff0c;文章底部有面试题。入参映射关键字说明图中paramenterTy…

php输出多余的空格或者空行

1&#xff0c;文件是否有bom。可以通过脚步检测&#xff0c;或者利用notepa打开&#xff0c;查看编码格式。 2. <?php echo something; ?> 或许是你的php标签外&#xff0c;有空格或者空行。一般的项目都是用框架&#xff0c;包含很多的文件&#xff0c;如果一个个文…

执行git命令时出现fatal: ‘origin‘ does not appear to be a git repository错误

执行git命令时出现fatal: ‘origin’ does not appear to be a git repository错误 在执行git pull origin master时出现&#xff1a;   fatal: ‘origin’ does not appear to be a git repository   致命提示:“origin”看起来不是一个git存储库   fatal: Could not r…

蒋涛作序盛赞Leo新作为“程序员职场实用百科全书”——《程序员羊皮卷》连载(1)

《程序员羊皮卷》当当购买地址&#xff1a;http://product.dangdang.com/product.aspx?product_id20691986 互动购买地址&#xff1a;http://www.china-pub.com/196049 程序员行业从外面看起来有很多绚丽的光环&#xff0c;这里有无数以程序致富的天才&#xff0c;世界首富比…

matlab ones函数_Matlab中相见恨晚的命令(持续更新)

知乎上有个“有哪些让人相见恨晚的Matlab命令”的话题&#xff0c;很多答主提供的命令确实很实用&#xff0c;为了更方便大家的学习&#xff0c;我就知乎上的答案和我自己想到的都综合整理成了一篇文章&#xff0c;把我觉得很实用的指令整理出来。知乎原答案链接dbstop if erro…

机器学习之特征工程

特征工程-概念 特征工程是一个面向十分广的概念&#xff0c;只要是在处理数据就可以认为是在做特征工程。个人理解&#xff0c;真正意义上的特征工程还是数据降维和数据升维的过程。 而前期对数据的处理过程&#xff1a; 需要哪些数据&#xff1f;数据如何存储&#xff1f;数…

ArcGIS AO开发高亮显示某些要素

参考代码1 ifeaturecursor pcur ifeatureclass.search(iqueryfilter pfilter); pfilter.whereclause strAddress; //输入查询条件&#xff0c;也就是你寸地址的字段名didian ifeature pfeat pcur.nextfeature();// 如果pCur多个要素&#xff0c;则可以考虑将其合并并一起高亮…

Oracle传输表空间介绍

传输表空间通过拷贝数据文件的方式&#xff0c;实现可跨平台的数据迁移&#xff0c;效率远超expdp/impdp, exp/imp等工具。还可以应用跨平台&数据库版本迁移表数据、归档历史数据和实现表空间级时间点数据恢复等场景。转载于:https://www.cnblogs.com/ilifeilong/p/7712654…

git push到GitHub的时候遇到! [rejected] master -> master (non-fast-forward)的问题

git push到GitHub的时候遇到! [rejected] master -> master (non-fast-forward)的问题 解决方法&#xff1a; 1、git pull origin master --allow-unrelated-histories //把远程仓库和本地同步&#xff0c;消除差异 2、重新add和commit相应文件 3、git push origin maste…

程序员考核的五大死因(上)

程序员作为企业开发力量的最核心资产&#xff0c;无疑得到公司从上至下的一致关注。开发是个智力密集型产业&#xff0c;程序开发的特点是&#xff0c;付出相同时间的情况下&#xff0c;两个开发者之间的产能会相差十几甚至几十倍。软件开发人员向来以“不容易考核、工作不容易…

du -sh 如何找到最大的文件夹_小白必看!手把手教你如何在linux上安装redis数据库...

首先我们要清楚redis是什么&#xff1f;redis是一种非关系型数据库&#xff0c;它与MySQL的这种关系型数据库不同&#xff0c;MySQL是将数据存储在磁盘中&#xff0c;而redis是储存在内存中。一般很多公司都是使用MySQLredis两种数据存储方式&#xff0c;这样可以提高性能&…

Linux删除特殊字符文件

1.删除带“-”的文件名的方法使用-- &#xff08;2个横杠&#xff09;#touch -- -%F-%T#rm -- -%F-%Trm: remove regular empty file -%F-%T?使用绝对路径并TAB特殊文件名#rm /root/-%F-%Trm: remove regular empty file /root/-%F-%T?2. 删除包含其它特殊字符的文件对于含有…

机器学习之线性回归 损失函数、代价函数、目标函数

损失函数&#xff08;Loss Function&#xff09;定义在单个样本上&#xff0c;算的是一个样本的误差。比如&#xff1a; 其中0-1损失函数: 感知器损失函数&#xff1a; 平方和损失函数&#xff1a; 绝对损失函数&#xff1a; 对数损失函数&#xff1a; 代价函数&#xff08;Cos…

bzoj4950(二分图最大匹配)

[Wf2017]Mission Improbable Time Limit: 1 Sec Memory Limit: 1024 MBSubmit: 105 Solved: 49[Submit][Status][Discuss]Description 那是春日里一个天气晴朗的好日子,你准备去见见你的老朋友Patrick,也是你之前的犯罪同伙。Patrick在编程竞赛上豪赌输掉了一大笔钱,所以他需…