热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringSecurity的学习与使用

SpringSecurity的学习与使用本文的1.SpringSecurity简介SpringSecurity本质是一个过滤器链,有很多过滤器2.SpringSecurity的过滤


Spring Security 的学习与使用


本文的


1.Spring Security 简介


Spring Security本质是一个过滤器链,有很多过滤器



2.SpringSecurity的过滤器加载过程


使用SpringSecurity配置过滤器


核心类: DelegatingFilterProxy



  • 首先进入 DelegatingFilterProxydoFilter() 方法中

  • 然后在这个方法中有这样一个 delegateToUse = initDelegate(wac);

  • 跟进去这个方法,可以看到这样一个 Filter delegate = wac.getBean(targetBeanName, Filter.class); ,这个获取的就是 FilterChainProxy

  • FilterChainProxy 中的 doFilter() 方法会调用 doFilterInternal() 方法,而这个方法中的 List filters = getFilters(fwRequest); 会获取Filter的集合并执行



3.SpringSecurity的两个核心接口


这两个接口是用来给我们自定义去开发的入口。


3.1 UserDetailsService


查询用户名密码的逻辑放在这个接口中。


具体的实现逻辑



  • 创建类继承UsernamePasswordAuthenticationFilter,并重写其中的 attemptAuthentication() 以及再上一级父类中的成功 successfulAuthentication() 和失败 unsuccessfulAuthentication 的方法.

  • 创建类实现 UserDetailsService ,编写查询数据过程,返回User对象,这个User对象是安全框架中定义的对象。


3.2 PasswordEncoder


用于加密的接口,在上面返回的User对象中的password字段可以使用这个官方的加密方法,SpringSecurity只支持这种加密方式。


4.SpringSecurity的权限方案-认证授权


认证就是用户名密码验证,有三种方案:通过配置文件、通过配置类、通过自定义编写 UserDetailsService 的实现类。



  • 通过配置文件,直接在 application.properties 文件中添加配置即可。


spring.security.user.name=hello
spring.security.user.password=world


  • 通过配置类


@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String password = passwordEncoder.encode("ppp");
auth.inMemoryAuthentication().withUser("qqq").password(password).roles("admin");
}
/**
* 这里使用的时候如果不声明这个bean,上面使用加密的地方会报错
* 所以这里要注册一个这个bean
* @return
*/
@Bean
PasswordEncoder password(){
return new BCryptPasswordEncoder();
}
}


  • 自定义实现类(常用)


在SpringSecurity中,会先去找配置文件和配置类,如果找到则使用,如果找不到,则会去找 UserDetailsService 的实现类


step1: 创建配置类,设置使用哪个 UserDetailsService 实现类


/**
* @Author: njitzyd
* @Date: 2020/11/1 22:57
* @Description: 使用自定义的实现完成securityConfig
* @Version 1.0.0
*/
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
/**
* 这里使用的时候如果不声明这个bean,上面使用加密的地方会报错
* 所以这里要注册一个这个bean
* @return
*/
@Bean
PasswordEncoder password(){
return new BCryptPasswordEncoder();
}
}

step2: 编写实现类,返回User对象,User对象有用户名密码和操作权限


@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UsersMapper usersMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println(usersMapper.selectById(1));
//调用usersMapper方法,根据用户名查询数据库
QueryWrapper wrapper = new QueryWrapper();
// where username=?
wrapper.eq("username",username);
Users users = usersMapper.selectOne(wrapper);
//判断
if(users == null) {//数据库没有用户名,认证失败
throw new UsernameNotFoundException("用户名不存在!");
}
List auths =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_sale");
//从查询数据库返回users对象,得到用户名和密码,返回
return new User(users.getUsername(),
new BCryptPasswordEncoder().encode(users.getPassword()),auths);
}
}

5.SpringSecurity实现记住我的功能



只需要配置一个bean,然后注入数据源,然后在配置中配置记住我就好,完整的配置:


@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
/**
* 注入数据源
*/
@Autowired
private DataSource dataSource;
/**
* 配置对象,实现记住我功能
* @return
*/
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
// 可以在启动的时候就创建表,也可以自己创建,建表语句在JdbcTokenRepositoryImpl的实现类中
//jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
/**
* 这里使用的时候如果不声明这个bean,上面使用加密的地方会报错
* 所以这里要注册一个这个bean
* @return
*/
@Bean
PasswordEncoder password(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//退出
http.logout().logoutUrl("/logout").
logoutSuccessUrl("/test/hello").permitAll();
//配置没有权限访问跳转自定义页面
http.exceptionHandling().accessDeniedPage("/unauth.html");
http.formLogin() //自定义自己编写的登录页面
.loginPage("/on.html") //登录页面设置
.loginProcessingUrl("/user/login") //登录访问路径
.defaultSuccessUrl("/success.html").permitAll() //登录成功之后,跳转路径
.failureUrl("/unauth.html")
.and().authorizeRequests()
.antMatchers("/","/test/hello","/user/login").permitAll() //设置哪些路径可以直接访问,不需要认证
//当前登录用户,只有具有admins权限才可以访问这个路径
//1 hasAuthority方法
// .antMatchers("/test/index").hasAuthority("admins")
//2 hasAnyAuthority方法,有其中的一个权限
// .antMatchers("/test/index").hasAnyAuthority("admins,manager")
//3 hasRole方法 ROLE_sale,点进去看源码可以看到,会给我们加一个ROLE_的前缀
.antMatchers("/test/index").hasRole("sale")
.anyRequest().authenticated()
// 设置记住我的功能
.and().rememberMe().tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(60)//设置有效时长,单位秒
.userDetailsService(userDetailsService);
// .and().csrf().csrfTokenRepository(COOKIECsrfTokenRepository.withHttpOnlyFalse());
// .and().csrf().disable(); //关闭csrf防护,就是跨站伪造
}
}

6.Spring Security中常用的注解


6.1 @Secured


判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“。


使用注解先要开启注解功能!


@EnableGlobalMethodSecurity(securedEnabled=true)


在控制器方法上添加注解


// 测试注解:
@RequestMapping("testSecured")
@ResponseBody
@Secured({"ROLE_normal","ROLE_admin"})
public String helloUser() {
return "hello,user";
}

6.2@PreAuthorize


先开启注解功能:


@EnableGlobalMethodSecurity(prePostEnabled = true)


@PreAuthorize:注解适合进入方法前的权限验证, @PreAuthorize 可以将登录用


户的 roles/permissions 参数传到方法中。


@RequestMapping("/preAuthorize")
@ResponseBody
//@PreAuthorize("hasRole('ROLE_管理员')")
@PreAuthorize("hasAnyAuthority('menu:system')")
public String preAuthorize(){
System.out.println("preAuthorize");
return "preAuthorize";
}

6.3@PostAuthorize


先开启注解功能:


@EnableGlobalMethodSecurity(prePostEnabled = true)


@PostAuthorize 注解使用并不多,在方法执行后再进行权限验证,适合验证带有返回值


的权限.


@RequestMapping("/testPostAuthorize")
@ResponseBody
@PostAuthorize("hasAnyAuthority('menu:system')")
public String preAuthorize(){
System.out.println("test--PostAuthorize");
return "PostAuthorize";
}

6.4@PostFilter


@PostFilter :权限验证之后对数据进行过滤 留下用户名是 admin1 的数据


表达式中的 filterObject 引用的是方法返回值 List 中的某一个元素


RequestMapping("getAll")
@PreAuthorize("hasRole('ROLE_管理员')")
@PostFilter("filterObject.username == 'admin1'")
@ResponseBody
public List getAllUser(){
ArrayList list = new ArrayList<>();
list.add(new UserInfo(1l,"admin1","6666"));
list.add(new UserInfo(2l,"admin2","888"));
return list;
}

6.5@PreFilter


@PreFilter: 进入控制器之前对数据进行过滤


@RequestMapping("getTestPreFilter")
@PreAuthorize("hasRole('ROLE_管理员')")
@PreFilter(value = "filterObject.id%2==0")
@ResponseBody
public List getTestPreFilter(@RequestBody List list){
list.forEach(t-> {
System.out.println(t.getId()+"\t"+t.getUsername());
});
return list;
}

参考文档




推荐阅读
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • 本文探讨了如何在Java/Javascript中建立防范CSRF攻击的机制。作者了解了CSRF的原理,并提供了前台和后台需要做的工作。同时,还介绍了一些比较好的例程供参考。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • 本文介绍了在Mac上安装Xamarin并使用Windows上的VS开发iOS app的方法,包括所需的安装环境和软件,以及使用Xamarin.iOS进行开发的步骤。通过这种方法,即使没有Mac或者安装苹果系统,程序员们也能轻松开发iOS app。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • JavaWeb中读取文件资源的路径问题及解决方法
    在JavaWeb开发中,读取文件资源的路径是一个常见的问题。本文介绍了使用绝对路径和相对路径两种方法来解决这个问题,并给出了相应的代码示例。同时,还讨论了使用绝对路径的优缺点,以及如何正确使用相对路径来读取文件。通过本文的学习,读者可以掌握在JavaWeb中正确找到和读取文件资源的方法。 ... [详细]
author-avatar
手机用户2502923495
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有