赞
踩
Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。
<!-- web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring安全控制 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
2.1 默认用户名: user,启动工程,控制台会输出,security随机生成的密码 如图:

2.2 访问项目根路径 localhost:8080,发现跳到了登录页

spring:
security:
user:
name: admin
password: 123123
```
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override//认证 protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 密码加密器,它实现了 PasswordEncoder 接口 BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); String password = passwordEncoder.encode("zhangsan"); auth.inMemoryAuthentication() //内存中进行校验 .withUser("zhangsan").password(password).roles("vip1"); } @Bean //由于加密时需要用到 PasswordEncoder接口,所以要放到容器中,否则报错 public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired //注入服务层, UserDetailsService userDetailsService; @Override//身份验证管理器生成器 protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean //由于加密时需要用到 PasswordEncoder接口,所以要放到容器中,否则报错 public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
// 1. 查看源码发现 Security的User类 需要传入用户名 密码 Collection 集合
// 2. 调用工具类中commaSeparatedStringToAuthorityList()方法创建权限集合
List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList("vip");
return new User("student",new BCryptPasswordEncoder().encode("student"),list);
}
}
// 授权 /** * login.html中form表单提交地址为 /user/login * .formLogin() * .loginPage("/login.html") 更改登录页面为自己编写的登录页 * .loginProcessingUrl("/user/login")登录访问路径 * .defaultSuccessUrl("/test/index").permitAll() 登录成功后,跳转路径 * * * .authorizeRequests().antMatchers( //授权:哪些路径需要什么角色访问 * 1. hasAuthority():当前用户具有指定的权限,返回true,否则 fals * 2. hasAnyAuthority():当前用户具有其中一个权限, 逗号分 * 3. hasRole() 方法 可查看源码,创建对象权限时,权限前缀为:ROLE_xx * 4. hasAnyRole:同 3,逗号分隔 * 5. anyRequest().authenticated()//所有请求都被访问 * 6. csrf().disable();//关闭csrf防护 */ protected void configure(HttpSecurity http) throws Exception { http.formLogin() //登录页面设置 .loginPage("/login.html") // .loginProcessingUrl("/user/login") .defaultSuccessUrl("/test/index").permitAll() .and().authorizeRequests() .antMatchers("/","/user/login").permitAll() .antMatchers("/vip1/").hasRole("vip1") // .antMatchers("/test/index").hasAuthority("admins") // .antMatchers("/test/index").hasAnyAuthority("admins,student") // .antMatchers("/test/index").hasRole("admins") // .antMatchers("/test/index").hasAnyRole("admins","sale") .anyRequest().authenticated() .and().csrf().disable(); // static目录下创建html页面 指定无权限访问页 http.exceptionHandling().accessDeniedPage("/denied.html"); }
配置类 或 主程序类添加注解 @EnableGlobalMethodSecurity() 详细见注释
/** * 认证授权注解使用 * 步骤: * 1. 启动类(配置类) 开启注解(需要哪个注解就开启哪个注解)@EnableGlobalMethodSecurity() * 2. 在controller的方法上面使用注解,设置角色 * 注解: * 1. @Secured:用户具有某个角色可以访问方法 * * 需要开启 securedEnabled = true, * 2. @PreAuthorize:注解适合进入方法前的权限验证,可以将登录用户的 roles/permissions参数传到方法中 * * 需要开启 prePostEnabled = true * * @PreAuthorize("hasAnyRole('ROLE_admins','ROLE_sale')") * 3. @PostAuthorize("hasAnyAuthority('admins')"):执行方法后,返回试图前 进行判断 * * 适合验证带有返回值的权限 */ @Controller public class SecurityTestController { // @Secured({"ROLE_sale","ROLE_admin1"}) // @PreAuthorize("hasAnyAuthority('admins')") // @PostAuthorize("hasAnyAuthority('admins')") @ResponseBody @RequestMapping("/update") @PostAuthorize("hasAnyAuthority('admins')") public String update() { System.out.println("test running..."); return "hello update"; } }
存在两个拦截器注解
@PostFilter:对方法返回数据进行过滤
/* 测试: 1. 添加@PostFilter注解 --> filterObject为内置对象 2. list集合内传入两条数据 */ @ResponseBody @RequestMapping("/update") @PreAuthorize("hasAnyAuthority('student')") @PostFilter("filterObject.username == '张三'") // 若用户名为 张三 则放行 public List<Users> update() { List<Users> list = new ArrayList<>(); list.add(new Users(1,"张三","123")); list.add(new Users(2,"李四","123")); System.out.println(list); return list; }


@PreFilter: 对传入方法数据进行过滤
注销功能: 在配置类中protected void configure(HttpSecurity http) 方法配置

记住我功能
实现原理

具体实现步骤

@Autowired
private DataSource dataSource;
@Bean
public PersistentTokenRepository persistentTokenRepository(){ //操作数据库对象,
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);//设置数据源,因为需要操作数据库
jdbcTokenRepository.setCreateTableOnStartup(true); //启动时自动创建表,如果存在该表则报错
return jdbcTokenRepository;
}
// 自动登录
http.rememberMe().tokenRepository(persistentTokenRepository()) //注入上面的数据库操作对象
.tokenValiditySeconds(60) //设置有效时长 (秒)
.userDetailsService(userDetailsService); //注入userDetailsService,用于获取登录的用户


启动项目进行测试:选择记住我登录成功后,查看数据库,发现成功自动创建表,并存在数据
关闭浏览器,重新访问其它页面,无需登录
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。