目录
SpringSecurity框架简介
Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。web应用的安全性主要包括2个方面,分别是用户认证和用户授权。
用户认证(authentication):验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。通俗点说就是系统认为用户是否能登录 。
用户授权(authorization):验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。通俗点讲就是系统判断用户是否有权限去做某些事情。
SpringSecurity特点
和spring无缝整合
全面的权限控制
专门为web开发而设计
旧版本不能脱离web环境使用
新版本对整个框架进行了分层抽取,分成了核心模块和web模块。单独引入核心模块就可以脱离web环境。
重量级
同类产品对比
Shiro:Apache 旗下的轻量级权限控制框架。
特点:
1)轻量级。Shiro 主张的理念是把复杂的事情变简单。针对对性能有更高要求的互联网应用有更好表现。
2)通用性。 好处:不局限于 Web 环境,可以脱离 Web 环境使用。缺陷:在 Web 环境下一些特定的需求需要手动编写代码定制。
一般来说,常见的安全管理技术栈的组合是这样的:
• SSM + Shiro
• Spring Boot/Spring Cloud + Spring Security
以上只是一个推荐的组合而已,如果单纯从技术上来说,无论怎么组合,都是可以运行的。
入门案例
第一步:创建springboot工程
第二步:引入相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
第三步:编写controller进行测试
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("hello")
public String hello() {
return "hello security";
}
}
第四步:在浏览器访问 localhost:8111/test/hello (Property文件改了端口为8111),重新定位到了下面这个页面:说明spring security 已经起作用了
默认用户名:user
默认密码:在启动台可以看到
spring security基本原理
本质是一个过滤器链。
FilterSecurityInterceptor:是一个方法级的权限过滤器, 基本位于过滤链的最底部
super.beforeInvocation(filterinvocation) 表示查看之前的 filter 是否通过。
filterinvocation.getChain().doFilter(filterinvocation.getRequest(), filterinvocation.getResponse());表示真正的调用后台的服务。
ExceptionTranslationFilter:是个异常过滤器,用来处理在认证授权过程中抛出的异常。
UsernamePasswordAuthenticationFilter:对/login 的 POST 请求做拦截,校验表单中用户
名,密码。
spring security过滤器加载过程
如果没有spring boot,单独使用spring security,使用spring security配置过滤器 DelegatingFilterProxy,找DelegatingFilterProxy的doFilter方法,doFilter方法里面有一行如下:
delegateToUse = this.initDelegate(wac);
进入到上面这个代码:
里面有一个系统内置的FilterChainProxy,FilterChainProxy把所有过滤器进行加载
spring security重要接口
UserDetailsService接口:当什么也没有配置的时候,账号和密码是由 Spring Security 定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。 所以我们要通过自定义逻辑控制认证逻辑。如果需要自定义逻辑时,只需要实现 UserDetailsService 接口即可。
查询数据库用户名和密码过程写在UserDetailService里面。
自己验证步骤:
1)创建类 继承UsernamePasswordAuthenticationFilter类,重写attemptAuthentication、successfulAuthentication、unsuccessfulAuthentication
2)创建类实现UserDetailService,编写查询过程,返回User对象,这个User对象是spring security框架提供的对象
PasswordEncoder :数据加密接口,用于返回User对象里面密码加密
web权限方案(认证+授权)
1、设置登录的用户名和密码
第一种方式:通过配置文件
第二种方式:通过配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
auth.inMemoryAuthentication().withUser("lucy").password(encoder.encode("lucy")).roles("admin");
}
@Bean
public PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
}
第三种方式:自定义编写实现类 UserDetailService
1) 创建配置类,设置使用哪个UserDetailService实现类
@Configuration
public class SecurityConfigTest extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Bean
public PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
}
2)编写接口的实现类,返回user对象,user对象有用户名、密码和操作权限
@Service("userDetailsService")
public class MyUserDetailService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
return new User("marry", new BCryptPasswordEncoder().encode("marry"),authorities);
}
}
2、自定义登录界面
1)完成配置
2)创建相关的页面和controller
注意:下面名字必须是username和password
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
用户名:<input type="text" name="username">
<br>
密码:<input type="text" name="password">
<br>
<input type="submit" value="login">
</form>
</body>
</html>
testController加一个方法
@GetMapping("index")
public String index() {
return "hello index";
}
验证:访问 http://localhost:8111/test/hello 可以直接访问
访问 http://localhost:8111/test/index 跳转我们自己写的登录界面 用户名密码成功之后 浏览器返回 hello index。