它是一个安全框架,主要能帮助我们做认证(你是谁)和授权(你能做什么)两大功能。
2.Springboot集成SpringSecurity(体验版)1.首先导入依赖
2.编写一个控制器。写一个映射方法。前端访问这个URL。你会发现会被Security拦截,需要输入用户名和密码。用户名security默认是user。密码默认是程序控制台上打印的。(Using generated security password: xxxxxxxx)
@Controllerpublic class HelloSecurityController { @GetMapping("/helloSecurity") @ResponseBody public String helloSecurity(){ return "helloSecurity"; }}
3、如果想要打破默认的security的用户名和密码(自定义登录与密码),只需在yaml配置如下:
spring: security: user: name: admin password: admin
3.基于内存版本的登录验证与角色权限管理假设现在有一个需求是这样的:给你一个部门管理系统。
系统有两个角色:USER,ADMIN。
有两个功能:
1)查看部门用户列表 (USER,ADMIN角色都可以使用)
2)删除部门某用户(ADMIN角色才能使用)
1、编写一个类继承WebSecurityConfigurerAdapter。重写configura方法。在方法中加入用户名和密码。并且在配置类上开启Security功能(@EnableWebSecurity)和
@EnableGlobalMethodSecurity(prePostEnabled = true)
注意:security5版本以上,需要密码加密。不然会出现一个passwordEncoder null 的异常.
@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)public class MySecurityConfig extends WebSecurityConfigurerAdapter { @Autowired PasswordEncoder passwordEncoder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("admin").password(passwordEncoder.encode("123456")).roles("ADMIN"); auth.inMemoryAuthentication().withUser("zs").password(passwordEncoder.encode("123456")).roles("USER"); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); }}
其次,在controller中加入这两个功能代码如下:
@GetMapping("/show/userList") @PreAuthorize(value = "hasAnyRole('USER','ADMIN')") @ResponseBody public String showUserList(){ return "展示部门用户列表(角色要求:USER/ADMIN)"; } @GetMapping("/deleteUser") @PreAuthorize(value = "hasAnyRole('ADMIN')") @ResponseBody public String deleteUser(){ return "删除某用户(角色要求:ADMIN)"; }
2、其次在用浏览器测试,你会发现zs,admin 都可以使用展示部门列表,但是删除功能只能是admin用户才可以。
注意:浏览器在测试的时候没换一个账户时,需要清除浏览器缓存在测试。 如果出现403错误,就表示被拒绝了,因为403错误页面是Springboot自带的。
3.最佳实战:基于数据库版本前面展示了基于内存版本的,现在升级为基于数据库版本的.
现在想要实现的是:项目首先进入登录页面,登录部门管理系统。登录成功后,部门管理系统会根据不同的角色控制他们的权限功能。
补充:SpringSecurity框架中的UserDetailsService 和 User 类UserDetails: 是一个接口,用来获取用户权限、密码、账户、判断账户是否锁定等操作。
user:是一个SpringSecurity高度抽象的用户类,实现了UserDetails接口。
所以如果你想基于数据库版本的。就必须实现UserDetailsService接口,重写里面的
public UserDetails loadUserByUsername(String username); 根据username去数据库登录登录校验查询。然后构建一个UserDetails 返回给security框架。
准备工作:
准备sys_user表,sys_role表,sys_user_role_relation表。
sys_user:
+-----------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| realName | varchar(255) | YES | | NULL | |
| username | varchar(255) | YES | | NULL | |
| password | varchar(255) | YES | | NULL | |
| accountNonExpired | tinyint(1) | YES | | 1 | |
| accountNonLocked | tinyint(1) | YES | | 1 | |
| credentialsNonExpired | tinyint(1) | YES | | 1 | |
| enabled | tinyint(1) | YES | | 1 | |
| createTime | date | YES | | NULL | |
+-----------------------+--------------+------+-----+---------+----------------+
sys_role:
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| role | varchar(255) | YES | | NULL | |
| describe | varchar(255) | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
sys_user_role_relation:
+--------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------+------+-----+---------+-------+
| userId | bigint(20) | NO | | NULL | |
| roleId | bigint(20) | NO | | NULL | |
+--------+------------+------+-----+---------+-------+
Dao层框架自定义,本次使用mybatisPlus。用mybatisplus自动生成对应的dao层代码。所以dao层代码全部省略了。
加入themeleaf依赖:
登录页面:
系统主页:
删除用户
查看用户列表页面:
删除用户页面:
自定义一个实体类MySecurityUser implement UserDetails。重写里面所有的方法。
编写一个UserDetailsService的实现类,重写loadUserByUsername方法。在方法中查询数据库构建MySecurityUser对象返回即可。
在WebSecurityConfigurerAdapter 这个类中改版不要基于内存的了,而是基于UserDetailsService的。
1.
@Datapublic class MySecurityUser implements UserDetails { private Long id; private String username; private String realName; private String password; private Integer accountNonExpired; private Integer accountNonLocked; private Integer credentialsNonExpired; private Integer enabled; private Date createTime; List
2.
@Component("MyUserDetailsImpl")public class MyUserDetailsImpl implements UserDetailsService { @Autowired ISys_userService iSys_userService; @Autowired ISys_user_role_relationService user_role_relationService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { MySecurityUser resUser = null; // 根据username查询 Sys_user sys_user = iSys_userService.getOne(new QueryWrapper
3.
@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled=true)public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("MyUserDetailsImpl") UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 改版基于userDetailsService 来实现数据库版本。 auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 表示哪些请求需要被放行。(首页/登录页/静态资源等允许放行) .antMatchers("/", "/static/**").permitAll() //而其他的请求都需要认证 .anyRequest() .authenticated() .and() // 设置自定义的登录页面url .formLogin() .loginPage("/index.html") //指定处理登录请求的路径,对应form表单的action地址 .loginProcessingUrl("/login.do").permitAll() // 指定错误时跳转到的url //.failureUrl("/error") // 指定登录成功跳转的url路径 .defaultSuccessUrl("/main.html",true); }}
4、假设现在数据库中的数据是这样的:
张三(zs),拥有USER角色。
管理员(admin),拥有ADMIN,USER两个角色。
项目测试会发现张三只能使用展示用户列表功能, 删除功能只能是拥有ADMIN角色的管理员才可以使用。
总结:本次记录自己学习security框架的成果。
版本3其实就是对于基于内存的改本。 加入了dao层的逻辑。
主要就是在
MyUserDetailsImpl类中 自己根据username 查询数据库自己构建一个UserDetails类扔给security框架而已。
如果我自己自己实现这种权限控制,大致思路就是在访问controller的时候,先经过过滤器或者拦截器。然后在此处判断该用户是否有资格访问该映射方法。如果有资格,放行。否者拦截。
后续有时间可以看看security的原理