Day19 SpringBoot 7 SpirngBootMyBatis SpringSecurity Thmeleaf与SpringSecurity
uwupu 啦啦啦啦啦

SpringBoot MyBatis整合

MyBatis的starter是MyBatis官方搞得,不是SpringBoot官方搞的

依赖

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>

使用/代码

  1. 添加依赖;

  2. 在application配置中添加DataSource配置和mybatis配置;

    • 添加mybatis的type-aliases-package和mapper-locations。其中type-aliases-package是pojo类的包名,mapper-locations是mapper文件的位置;

      1
      2
      3
      mybatis:
      type-aliases-package: com.yn.springbootwebstudy4_mybatis.pojo
      mapper-locations: classpath:mybatis/mapper/*.xml # 这里是resources下的mybatis/mapper文件夹下的所有xml文件
    • 添加DataSource配置。添加spring.datasource下的username、password、url和driver-class-name配置。

      1
      2
      3
      4
      5
      6
      spring:
      datasource:
      username: root # 用户名
      password: 123456
      url: jdbc:mysql://localhost:3306/springbootstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
      driver-class-name: com.mysql.cj.jdbc.Driver
  3. 创建Mapper接口,使用@Mapper注解和@Repository注解;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Mapper  //表示这是一个MyBatis的Mapper类
    @Repository
    public interface UserMapper {

    List<User> queryUserList();
    User queryUserById(Integer id);
    int addUser(User user);
    int updateUser(User user);
    int deleteUser(Integer id);
    }
  4. 在mapper-locations指定的位置创建Mapper的xml文件,并配置相关内容。

    image

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <mapper namespace="com.yn.springbootwebstudy4_mybatis.mapper.UserMapper">
    <cache/>
    <select id="queryUserList" resultType="User" useCache="true">
    select * from user;
    </select>
    <select id="queryUserById" parameterType="int" resultType="User">
    select * from user where id=#{id}
    </select>
    <insert id="addUser" parameterType="User">
    insert into user(username,password,nickname,regDate) values(#{username},#{password},#{nickname},#{regDate})
    </insert>
    <delete id="deleteUser" parameterType="int">
    delete from user where id=#{id}
    </delete>
    <update id="updateUser" parameterType="User">
    update user set username=#{username},password=#{password},nickname=#{nickname},regDate=#{regDate} where id=#{id};
    </update>
    </mapper>
  5. 使用@Autowired注解使用即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    @RestController
    public class UserController {
    @Autowired
    private UserMapper userMapper;

    @GetMapping("/user/list")
    public List<User> queryUserList(){
    List<User> users = userMapper.queryUserList();
    return users;
    }
    @GetMapping("/user/get/{id}")
    public User queryUserById(@PathVariable("id") Integer id){
    return userMapper.queryUserById(id);
    }

    @GetMapping("/user/add")
    public int addUser(User user){
    return userMapper.addUser(user);
    }
    @GetMapping("/user/delete/{id}")
    public int deleteUser(@PathVariable("id") Integer id){
    return userMapper.deleteUser(id);
    }
    @GetMapping("/user/update")
    public int updateUser(User user){
    return userMapper.updateUser(user);
    }
    }

ResultMap复习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.yn.springbootwebstudy2.mapper.EmployeeMapper">
<resultMap id="Employee" type="Employee">
<id column="id" property="id" />
<result column="lastname" property="lastName"/>
<result column="email" property="email" />
<result column="gender" property="gender"/>
<result column="birth" property="birth" jdbcType="DATE" javaType="Date"/>
<collection property="department" ofType="Department">
<id column="id" property="id"/>
<result column="dname" property="departmentName"/>
</collection>
</resultMap>
<insert id="add" parameterType="Employee">
insert into employee(lastName,email,gender,department,birth) values(#{lastName},#{email},#{gender},#{department.id},#{birth})
</insert>
<select id="get" resultMap="Employee">
select * from employee where id=#{id}
</select>
<select id="getList" parameterType="Integer" resultMap="Employee">
SELECT e.id id,lastname,email,gender,birth,department,departmentname 'dname' from department d,employee e WHERE d.id=e.department;
</select>
<delete id="delete" parameterType="int">
delete from employee where id=#{id}
</delete>
<update id="update" parameterType="Employee">
update employee set lastname=#{lastName},email=#{email},gender=#{gender},birth=#{birth},department=#{department.id} where id=#{id}
</update>

</mapper>

Spring Security(安全)

sudo rm -rf /* 以管理员身份sudo 删除ReMove -垃圾文件RubbishFile 根目录下/所有文件*

Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.

Spring Security是一个强大的可高度自定义的认证和访问控制框架。它是对于保护Spring应用实际上的标准。

引入

实现方式:shiro、SpringSecurity。

认证、授权

原理:AOP切面

简介

Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的计数选型,可以实现强大的Web安全控制。对于安全控制,仅需要引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理。

  • WebSecurityConfigurerAdapter:自定义的Security策略;
  • AuthenticationManagerBuilder:自定义认证策略;
  • @EnableWebSecurity:开启WebSecurity模式

Spring Security的两个主要目标:认证、授权(访问控制)。

认证:Authentication

授权:Authorization

依赖

1
2
3
4
5
<!--Security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

认证和授权(新)

2022.09.13

来自WebSecurityConfigurerAdapter的启示

1
2
3
Deprecated
Use a SecurityFilterChain Bean to configure HttpSecurity or
a WebSecurityCustomizer Bean to configure WebSecurity

使用一个SecurityFilterChain Bean去配置HttpSecurity;

使用一个WebSecurityCustomizer Bean去配置WebSecurity;

方法

  1. 创建配置类使用@EnableWebSecurity注解;

  2. 创建@Bean,两个:

    • 认证:为角色分配可访问的页面

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      @Bean
      public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
      http.authorizeHttpRequests()
      .antMatchers("/").permitAll()//为所有用户授权根目录
      .antMatchers("/level1/**").hasRole("vip1")//为vip1授权/level1/**目录。
      .antMatchers("/level2/**").hasRole("vip2")
      .antMatchers("/level3/**").hasRole("vip3");


      http.formLogin();//使用默认生成的登录页面
      http.csrf().disable();//禁用csrf防御
      http.logout().logoutSuccessUrl("/");//登出后跳到根目录页面

      http.rememberMe();//“记住我”,在浏览器添加一个cookie,默认保存两周时间
      //在此之前,一律为关闭浏览器即关闭会话,会自动退出登录。

      http.formLogin().loginPage("/login")//自定义登录页
      .loginProcessingUrl("/loginxx")//修改登录时post的url,默认/login
      .usernameParameter("u")//修改表单的用户名的key,默认username
      .passwordParameter("p");//修改表单的密码的key,默认password
      // .failureForwardUrl("/login")//失败时跳转,默认/login?error。
      // .successForwardUrl("/")//成功时跳转页面,默认为登录前页面,若没有登录前页面,则为主页。
      return http.build();
      }
    • 授权:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      @Bean
      public UserDetailsService userDetailsService() {
      BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
      UserDetails[] user = {
      User.withDefaultPasswordEncoder().username("root").password("123456").roles("vip1","vip2","vip3").build(),
      User.withDefaultPasswordEncoder().username("zhangsan").password("123456").roles("vip1","vip2").build(),
      User.withDefaultPasswordEncoder().username("lisi").password("123456").roles("vip1").build()
      };
      return new InMemoryUserDetailsManager(user);
      }

HttpSecurity的一些方法

  • .antMatchers(“/“).permitAll()//为根目录允许所有
  • .antMatchers(“/level1/**“).hasRole(“vip1”)//为level1目录分配vip1角色
  • **http.formLogin():若没有使用FormLoginConfigurer.logPage(String)**指定登录页,将生成一个默认的登录页;
  • **http.csrf().disable()**:禁用csrf防御;
  • **http.logout().logoutSuccessUrl(“/“)**:登出成功后跳到根目录页面。
  • **http.rememberMe()**:在登录页添加“记住我”checkbox,若为true,则登录时会在浏览器添加一个cookie,默认保存两周时间,保持用户登录。在此之前,一律为关闭浏览器即关闭会话,会自动退出登录。
    • http.rememberMe().rememberMeParameter(“rem”) 修改”记住我”的key,默认为remember-me
  • **http.formLogin()**,可以定义登录API的相关参数
    • loginPage(“/login”)//自定义登录页
    • .loginProcessingUrl(“/loginxx”) 修改登录时post的url,默认/login
    • .usernameParameter(“u”) 修改表单的用户名的key,默认username
    • .passwordParameter(“p”) 修改表单的密码的key,默认password
    • .failureForwardUrl(“/login”) 失败时跳转,默认/login?error。
    • .successForwardUrl(“/“) 成功时跳转页面,默认为登录前页面,若没有登录前页面,则为主页。

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@EnableWebSecurity
@Configuration
public class FormLoginSecurityConfig{
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");


http.formLogin();//使用默认生成的登录页面
http.csrf().disable();//禁用csrf防御
http.logout().logoutSuccessUrl("/");//登出后跳到根目录页面

http.rememberMe();//“记住我”,在浏览器添加一个cookie,默认保存两周时间
//在此之前,一律为关闭浏览器即关闭会话,会自动退出登录。

http.formLogin().loginPage("/login")//自定义登录页
.loginProcessingUrl("/loginxx")//修改登录时post的url,默认/login
.usernameParameter("u")//修改表单的用户名的key,默认username
.passwordParameter("p");//修改表单的密码的key,默认password
// .failureForwardUrl("/login")//失败时跳转,默认/login?error。
// .successForwardUrl("/")//成功时跳转页面,默认为登录前页面,若没有登录前页面,则为主页。
return http.build();
}

@Bean
public UserDetailsService userDetailsService() {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
UserDetails[] user = {
User.withDefaultPasswordEncoder().username("root").password("123456").roles("vip1","vip2","vip3").build(),
User.withDefaultPasswordEncoder().username("zhangsan").password("123456").roles("vip1","vip2").build(),
User.withDefaultPasswordEncoder().username("lisi").password("123456").roles("vip1").build()
};
return new InMemoryUserDetailsManager(user);
}
}

自定义登录页

在@Bean的SecurityFilterChain securityFilterChain(HttpSecurity http)下使用http.formLogin().loginPage("/login")指定登录页后,登录页需要适配springBoot的api。

API

默认

url:http://127.0.0.1:8080/login

form:username=root&password=123456&remember-me=on

1
2
3
4
5
{
username:"root",
password:"123456",
"remember-me":"on"
}

上面的示例

url:http://127.0.0.1:8080/loginxx

form:u=root&p=123456&rem=on

1
2
3
4
5
{
u:"root",
p:"123456",
rem:"on"
}

Thmeleaf与Spring Security整合

可以在templates下页面上使用sec属性标签来控制页面内容。

依赖

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
<!--Security-thymeleaf整合-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>


<!--Security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

html

1
2
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">

使用方法

sec:authorize="isAuthenticated()"为例

  1. 添加依赖和html的xmlns;

  2. 代码:

    1
    <div sec:authorize="isAuthenticated()">asd</div>

    这里表示,若已登录,则显示该部分div,否则不显示该部分div。

一些属性

  • **sec:authorize=””**:内含判断条件,若条件成立,则显示该部分组件。如:

    1
    <div sec:authorize="isAuthenticated()">asd</div>

    则表示当SpringSecurity的验证系统登录后,则显示该部分内容。

    • **isAuthenticated()**:是否已经登录;
    • **hasRole(‘vip2’)**:登录的用户是否拥有role vip2。
  • **sec:authentication=””**:内含一些变量,运行后会将变量的值放在元素的innerHTML中;

    • name:用户名;
    • principal.authorities:用户的角色,为数组。

其他

MVC

M:数据和业务

C:交接

V:HTML

认证和授权(旧)

WebSecurityConfigurerAdapter过时

方法

  1. 创建SecurityConfig配置类,使用@EnableWebSecurity注解,继承WebSecurityConfigurerAdapter类

    1
    2
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {...}
  2. 重写configure的两个方法,分别为configure(HttpSecurity http)configure(AuthenticationManagerBuilder auth)。第一个用于认证,即为不同url分配不同的角色。第二个用于授权,为不同的用户分配不同的角色。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    //授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests()
    .antMatchers("/").permitAll()//为根目录允许所有
    .antMatchers("/level1/**").hasRole("vip1")//为level1目录分配vip1角色
    .antMatchers("/level2/**").hasRole("vip2")
    .antMatchers("/level3/**").hasRole("vip3");

    http.formLogin();//使用默认生成的登录页面
    http.csrf().disable();//禁用csrf防御
    http.logout().logoutSuccessUrl("/");//登出后跳到根目录页面
    }

    //认证,SpringBoot
    //密码编码:PasswordEncoder
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //应该在数据库中,这里用自定义用于演示
    auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
    .withUser("lisi").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")//为用户名lisi分配角色vip2和vip3.
    .and()//拼接
    .withUser("zhangsan").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1")
    .and()
    .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
    }

HttpSecurity的一些方法

  • .antMatchers(“/“).permitAll()//为根目录允许所有
  • .antMatchers(“/level1/**“).hasRole(“vip1”)//为level1目录分配vip1角色
  • **http.formLogin():若没有使用FormLoginConfigurer.logPage(String)**指定登录页,将生成一个默认的登录页;
  • **http.csrf().disable()**:禁用csrf防御;
  • **http.logout().logoutSuccessUrl(“/“)**:登出成功后跳到根目录页面。

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.yn.config;
import ...;


@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");

//没有权限,默认到登录页面

http.formLogin();
}

//认证,SpringBoot
//密码编码:PasswordEncoder
//SpringSecurity 5.0+ 新增许多加密方式
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//应该在数据库中,这里用自定义用于演示
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("lisi").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
.and()
.withUser("zhangsan").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
}
}

 评论