springboot安全管理 safe

学习目标

1、 了解Spring Boot的默认安全管理

2、 掌握自定义用户认证的实现

3、 掌握自定义用户授权管理的实现

4、 掌握Security实现页面控制的实现

(一)创建简单的电影展示页面

  1. 引入依赖

<!-- SecurityThymeleaf整合实现前端页面安全访问控制 -->

<dependency>

<groupId>org.thymeleaf.extras</groupId>

<artifactId>thymeleaf-extras-springsecurity5</artifactId>

</dependency>

  1. 将index.html页面引入到resource文件夹下
  2. 将detail文件夹复制到templates文件夹下

 

  1. 新建FilmeController 控制类

//影片详情

@GetMapping("detail/{type}/{path}")

public String toDetail(@PathVariable("type") String type,

@PathVariable("path") String path){

return "detail/"+type+"/"+path;

}

  1. 测试

http://localhost:8080/index.html 或者 http://localhost:8080

(二)引入安全控制(框架自带)

  1. 引入依赖

<!-- 开启spring security安全验证-->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-security</artifactId>

</dependency>

  1. 测试

观察控制台显示的内容。(仅引入上面依赖,没有添加任何启动安全验证。框架自动做了安全验证,浏览页面自动跳转到登录页面)

访问任意路径均自动跳转到了登录页面。该登录页面是框架建立。

http://localhost:8080/index.html 或者 http://localhost:8080

 

(三)内存身份认证(以下三种均为用户自定义)

  1. 新建SecurityConfig配置类

//@EnableWebSecurity @Configuration @Import @EnableGlobalAuthentication组合用法

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {

}

  1. 使用内存进行身份认证

新建方法,并添加下面代码:

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception{

//1. 内存身份验证

//设置密码编码器(仅限于学习、测试用)

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

//设置内存用户信息(仅限于学习、测试用)

auth.inMemoryAuthentication().passwordEncoder(encoder)

.withUser("shitou").password(encoder.encode("123456")).roles(("common"))

.and()

.withUser("admin").password(encoder.encode("123456")).roles(("vip"));

}

  1. 测试

输入用户名和密码,可以正常跳转到首页。

此种方法仅限于学习测试用,生产环境不可用(比赛中如果实在想不到其他方法,可以用。但可能会扣些分)。

 

(四)JDBC身份认证

  1. 往t_customer 和 t_authority插入数据

insert into t_customer values('1','shitou','$2a$10$PlJATR.VawcPErOc2ckjAutzFZZYzyumSQkFNMxQG74eWFzhk8Axe','1'),

('2','admin','$2a$10$PlJATR.VawcPErOc2ckjAutzFZZYzyumSQkFNMxQG74eWFzhk8Axe','1');

 

PS: 如何获得密码的密文:

//此方法也可以用在比赛中验证密码

@Test

void contextLoads() {

String password = "123456";

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

String encodPwd = encoder.encode(password);

System.out.println("加密后的密码为:" + encodPwd);

// 校验这两个密码是否是同一个密码

// $2a$10$PlJATR.VawcPErOc2ckjAutzFZZYzyumSQkFNMxQG74eWFzhk8Axe

// matches方法第一个参数是原密码,第二个参数是加密后的密码

boolean matches = encoder.matches(password, encodPwd);

System.out.println("两个密码一致:" + matches);

}

  1. 添加依赖

<!-- JDBC数据库连接启动器 -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-jdbc</artifactId>

</dependency>

<!-- MySQL数据连接驱动 -->

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>8.0.32</version>

<scope>runtime</scope>

</dependency>

  1. 数据库配置连接

# MySQL???????

spring.datasource.url=jdbc:mysql://localhost:3306/blog_system?serverTimezone=UTC

spring.datasource.username=root

spring.datasource.password=root123

  1. 使用JDBC进行验证

protected void configure(AuthenticationManagerBuilder auth) throws Exception{

//2 JDBC验证(核心还是通过查询用户信息进行验证)

String userSQL ="select username,password,valid from t_customer " +

"where username = ?";

String authoritySQL="select c.username,a.authority from t_customer c,t_authority a,"+

"t_user_authority ca where ca.user_id=c.id " +

"and ca.authority_id=a.id and c.username =?";

auth.jdbcAuthentication().passwordEncoder(encoder)

.dataSource(dataSource)

.usersByUsernameQuery(userSQL)

.authoritiesByUsernameQuery(authoritySQL);

}

  1. 测试

输入用户名和密码,可以正常跳转到首页。

(五)使用UserDetailsService进行身份认证

  1. 新建CustomerService 服务类

方法一:根据用户名查询用户信息

首先从redis获取,若redis不存在,则从数据库查询,存在则放入redis

@Autowired

private CustomerRepository customerRepository;

// @Autowired

// private AuthorityRepository authorityRepository;

@Autowired

private RedisTemplate redisTemplate;

public Customer getCustomer(String username){

Customer customer=null;

//首先从redis查询用户信息

Object o = redisTemplate.opsForValue().get("customer_"+username);

if(o!=null){

customer=(Customer)o;

}else {

customer = customerRepository.findByUsername(username);

if(customer!=null){

redisTemplate.opsForValue().set("customer_"+username,customer);

}else{

return null ; //应该抛出记录不存在的异常

}

}

return customer;

}

方法二:业务控制:使用唯一用户名查询用户权限

根据用户名查询权限信息。

首先从redis获取,若redis不存在,则从数据库查询,存在则放入redis

  1. 定义实现类 UserDetailsServiceImpl

@Service

public class UserDetailsServiceImpl implements UserDetailsService {

@Autowired

private CustomerService customerService;

@Override

public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

// 通过业务方法获取用户及权限信息

Customer customer = customerService.getCustomer(s);

List<Authority> authorities = customerService.getCustomerAuthority(s);

// 对用户权限进行封装(可能有多权限)

List<SimpleGrantedAuthority> list = authorities.stream().map(authority -> new SimpleGrantedAuthority(authority.getAuthority())).collect(Collectors.toList());

// 返回封装的UserDetails用户详情类

if(customer!=null){

UserDetails userDetails= new User(customer.getUsername(),customer.getPassword(),list);

return userDetails;

} else {

// 如果查询的用户不存在(用户名不存在),必须抛出此异常

throw new UsernameNotFoundException("当前用户不存在!");

}

}

}

  1. 使用UserDetailsService进行身份认证 SecurityConfig

protected void configure(AuthenticationManagerBuilder auth) throws Exception{

// 3、使用UserDetailsService进行身份认证

auth.userDetailsService(userDetailsService).passwordEncoder(encoder);

}

  1. redis序列化

新增 RedisConfig 配置类。源码略。

输入用户名和密码验证

(六)自定义用户访问控制(以下均为自定义用户授权管理内容)

6.1 自定义用户访问 SecurityConfig

/**

* 自定义用户访问控制

* @param http

* @throws Exception

*/

@Override

protected void configure(HttpSecurity http) throws Exception{

// 自定义用户授权管理

http.authorizeRequests()

.antMatchers("/").permitAll()

// 需要对static文件夹下静态资源进行统一放行

.antMatchers("/login/**").permitAll()

.antMatchers("/detail/common/**").hasRole("common") //普通权限可以访问

.antMatchers("/detail/vip/**").hasRole("vip") //vip权限才可以访问

.anyRequest().authenticated();

}

测试。不同权限用户登录测试验证。重启启动服务器后,刷新静态页面不会跳转到登录页面,因为对静态页面进行放行。

6.2 自定义登录页面(用户权限:shitou 均无法访问详细页面)

  1. 编写登录页面 login.html(并将css控制添加到resource文件夹下)

  1. 自定义用户登录跳转

@GetMapping("/userLogin")

public String toLogin(){

return "login/login";

}

  1. 自定义用户登录控制 SecurityConfig

@Override

protected void configure(HttpSecurity http) throws Exception{

// 自定义用户登录控制

http.formLogin()

.loginPage("/userLogin").permitAll()

.usernameParameter("name").passwordParameter("pwd")

.defaultSuccessUrl("/")

.failureUrl("/userLogin?error");

}

  1. 测试(正常登录到首页)

6.3自定义用户退出

  1. 在inde.html主页添加

<form th:action="@{/mylogout}" method="post">

<input th:type="submit" th:value="注销" />

</form>

  1. 自定义用户退出控制
  2. SecurityConfig

@Override

protected void configure(HttpSecurity http) throws Exception{

// 自定义用户退出控制

http.logout()

.logoutUrl("/mylogout")

.logoutSuccessUrl("/");

  1. 测试

(七)用户登录信息获取

  1. 通过传统的HttpSession获取Security控制的登录用户信息

详见: FilmeController 的getUser 方法

测试 http://localhost:8080/getuserBySession

  1. 通过Security提供的SecurityContextHolder获取登录用户信息

详见: FilmeController 的getUser2 方法

测试 http://localhost:8080/getuserByContext

(八)登录界面 记住我功能 实现

8.1 基于简单加密token的方式

  1. 在登录页面login.html添加代码

<div class="checkbox mb-3">

<label>

<input type="checkbox" name="rememberme"> 记住我

</label>

</div>

  1. 配置类

@Override

protected void configure(HttpSecurity http) throws Exception{

// 定制Remember-me记住我功能

http.rememberMe()

.rememberMeParameter("rememberme")

.tokenValiditySeconds(10000) //失效时间 毫秒

}

  1. 测试

8.2 基于持久化token的方式

  1. 新建 persistent_logins 表

 

  1. 配置文件类 SecurityConfig

@Override

protected void configure(HttpSecurity http) throws Exception{

// 定制Remember-me记住我功能

http.rememberMe()

.rememberMeParameter("rememberme")

.tokenValiditySeconds(10000) //失效时间 毫秒

// cookie信息进行持久化管理

.tokenRepository(tokenRepository());

}

/**

* 持久化Token存储

* @return

*/

@Bean

public JdbcTokenRepositoryImpl tokenRepository(){

JdbcTokenRepositoryImpl jr=new JdbcTokenRepositoryImpl();

jr.setDataSource(dataSource);

return jr;

}

  1. 测试

(九)CSRF防护

  1. 在templates下添加静态页面 csrfTest.html页面

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>

<form method="post" action="/updateUser">

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/> (注释掉此行)

用户名: <input type="text" name="username" /><br />

密&nbsp;&nbsp;码: <input type="password" name="password" /><br />

<button type="submit">修改</button>

</form>

使用了thymeleaf模板。 th:action="@{/updateUser}"自动携带了csrf的token

<form method="post" th:action="@{/updateUser}">

<!-- <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>-->

用户名: <input type="text" name="username" /><br />

密&nbsp;&nbsp;码: <input type="password" name="password" /><br />

<button type="submit">修改</button>

</form>

  1. 新建CSRFController

@Controller

public class CSRFController {

// 向用户修改页跳转

@GetMapping("/toUpdate")

public String toUpdate() {

return "csrf/csrfTest";

}

// 用户修改提交处理

@ResponseBody

@PostMapping(value = "/updateUser")

public String updateUser(@RequestParam String username, @RequestParam String password,

HttpServletRequest request) {

System.out.println(username);

System.out.println(password);

String csrf_token = request.getParameter("_csrf");

System.out.println(csrf_token);

return "ok";

}

}

  1. 测试 会报错,证明被拦截。

关闭csrf拦截 SecurityConfig

/**

* 自定义用户访问控制

* @param http

* @throws Exception

*/

@Override

protected void configure(HttpSecurity http) throws Exception{

// 可以关闭Spring Security默认开启的CSRF防护功能

http.csrf().disable();

}

再次测试验证。

(十)Security管理前端页面

  1. 添加依赖

<!-- SecurityThymeleaf整合实现前端页面安全访问控制 -->

<dependency>

<groupId>org.thymeleaf.extras</groupId>

<artifactId>thymeleaf-extras-springsecurity5</artifactId>

</dependency>

  1. index.html主页添加代码

<h2 align="center"><span sec:authentication="name" style="color: #007bff"></span>您好,您的用户权限为<span sec:authentication="principal.authorities" style="color:darkkhaki"></span>,您有权观看以下电影</h2>

  1. 测试

项目结构:

附件:依赖

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-groovy-templates</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mustache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!-- 开启spring security安全验证-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- JDBC数据库连接启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- MySQL数据连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Data JPA操作数据库 编写类时 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Redis缓存启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- get set-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<!-- Security与Thymeleaf整合实现前端页面安全访问控制 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
</dependencies>

附件2:application.properties配置(注意使用到了redis)

# MySQL???????
spring.datasource.url=jdbc:mysql://localhost:3306/blog_system?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root123

# Redis?????
spring.redis.host=127.0.0.1
# Redis???????
spring.redis.port=6379
# Redis?????????????
spring.redis.password=

# thymeleaf??????????true?????????????false???????????true
spring.thymeleaf.cache=false

server.port=8081

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
## 介绍 使用 spring boot,基于 ssm 框架和 shiro 安全框架,开发的一个物流管理系统。前端使用的是 H-ui 开源框架,运用了 Bootstrap table、zTree、PageHelper、jQuery validate 等插件。 ## 特点 1. 基于 spring boot、maven 构建; 2. 运用了 springspring mvc、mybatis 和 shiro 框架; 3. 采用了 RBAC 的思路设计系统,采用了 Mysql 作为数据库支持; 4. 不同的角色登录系统会有不同的菜单列表,且会根据角色返回特定的数据; 5. 拥有基础数据管理模块,管理管理模块,角色管理模块,权限管理模块,客户管理模块,订单管理模块和业务处理模块; 6. 能够实现完整的业务流程:添加客户、添加订单、订单处理、财务报表。 ## 细节介绍 1. 业务员访问时,只能访问客户管理、订单管理、业务处理菜单,且只有添加的权力,没有修改和删除的权力; 2. 业务员添加订单时,只能基于自己拥有的客户添加; 3. 业务经理拥有客户管理、订单管理、业务处理的所有功能,可以查看所有业务员的客户和订单; 4. 总经理角色可以查看所有数据,但是没有修改的权力; 5. 仓管员只有业务处理中,测量物品信息和入库的功能,其他数据不可修改; 6. 财务可以查看审核订单价格详情并导出为 excel 表格。 -------- <项目介绍> 该资源内项目源码是个人的毕设,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 --------

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值