欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

记录自己学习springSecurity基本使用

时间:2023-06-07
1.什么是SpringSecurity,能做什么?

它是一个安全框架,主要能帮助我们做认证(你是谁)和授权(你能做什么)两大功能。

2.Springboot集成SpringSecurity(体验版)

1.首先导入依赖

org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.projectlombok lombok 1.18.20 org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin

 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依赖:

org.springframework.boot spring-boot-starter-thymeleaf

  前端页面(随便写一下):

登录页面:

Spring Security Example Invalid username and password. You have been logged out.

系统主页:

主页 查看用户
删除用户

查看用户列表页面:

展示用户展示所有用户(角色要求:ADMIN/USER)

删除用户页面:

Title删除用户(角色要求:ADMIN)

后端Java:

自定义一个实体类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 authorityList; // 该用户的角色列表集合 @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorityList; } @Override public String getPassword() { return this.password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return accountNonExpired==1; } @Override public boolean isAccountNonLocked() { return accountNonLocked==1; } @Override public boolean isCredentialsNonExpired() { return credentialsNonExpired==1; } @Override public boolean isEnabled() { return enabled==1; }}

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().eq("username", username)); if(sys_user!=null){ // 构建一个UserDetails对象给框架。 resUser = new MySecurityUser(); BeanUtils.copyProperties(sys_user,resUser); // 查询该username用户的权限 List authorities = user_role_relationService.getRoleByUserId(resUser.getId()); resUser.setAuthorityList(authorities); } return resUser; }}// 我这里构建username用户权限的代码是如下。重点想表达的意思是:角色名字前面需要加入 ROLE_ 这是security框架规定的。 @Override public List getRoleByUserId(Long userId) { List list = user_role_relationMapper.getRoleByUserId(userId); List collect = list.stream().map((role) -> { GrantedAuthority g = new SimpleGrantedAuthority("ROLE_" + role.getRole()); return g; }).collect(Collectors.toList()); return collect; }

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的原理

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。