spring学习之springSecurity(三)

我爱海鲸 2022-11-07 00:41:46 暂无标签

简介web鉴权

链接上一篇文章:spring学习之springSecurity(一)

1、设置登录系统的账号、密码

方式一:在application.properties

spring.security.user.name=woaihaijin
spring.security.user.password=woaihaijin

配置账号密码之后,console中就不会打印相关的密码了

在登录页面重新输入配置的账号密码:

方式二:编写类实现接口

@Configuration
public class SecurityConfig {
// 注入 PasswordEncoder 类到 spring 容器中
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
 }
}

登录逻辑

/**
 * @author: haijin
 * @Date: 2022/11/06 15:24
 */
@Service
public class LoginServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 判断用户名是否存在
        if (!"admin".equals(username)){
            throw new UsernameNotFoundException("用户名不存在!");
        }
        // 从数据库中获取的密码 atguigu 的密文
        String pwd = "$2a$10$9fnh2SvGk/CjRKTGMYBtBOBAqhQ9iKdHot2/6Aj.MaXYycxySKYw.";
        // 第三个参数表示权限
        return new User(username,pwd,AuthorityUtils.commaSeparatedStringToAuthorityList("admin,"));
    }

}

项目截图:

2、实现数据库认证来完成用户登录

完成自定义登录

准备 sql

CREATE TABLE users ( id BIGINT PRIMARY KEY auto_increment, username VARCHAR ( 20 ) UNIQUE NOT NULL, PASSWORD VARCHAR ( 100 ) );-- 密码 woaihaijing
INSERT INTO users
VALUES
	( 1, '张三', '$2a$10$X4pNxnbDQiGRpb.2gaYeR.2Ut5/l02fVsepHJkSirFG3QmowZVmeW' );-- 密码 woaihaijing
INSERT INTO users
VALUES
	( 2, '李四', '$2a$10$X4pNxnbDQiGRpb.2gaYeR.2Ut5/l02fVsepHJkSirFG3QmowZVmeW' );

CREATE TABLE role ( id BIGINT PRIMARY KEY auto_increment, NAME VARCHAR ( 20 ) );
INSERT INTO role
VALUES
	( 1, '管理员' );
INSERT INTO role
VALUES
	( 2, '普通用户' );

CREATE TABLE role_user ( uid BIGINT, rid BIGINT );
INSERT INTO role_user
VALUES
	( 1, 1 );
INSERT INTO role_user
VALUES
	( 2, 2 );

CREATE TABLE menu ( id BIGINT PRIMARY KEY auto_increment, NAME VARCHAR ( 20 ), url VARCHAR ( 100 ), parentid BIGINT, permission VARCHAR ( 20 ) );
INSERT INTO menu
VALUES
	( 1, '系统管理', '', 0, 'menu:system' );
INSERT INTO menu
VALUES
	( 2, '用户管理', '', 0, 'menu:user' );

CREATE TABLE role_menu ( mid BIGINT, rid BIGINT );
INSERT INTO role_menu
VALUES
	( 1, 1 );
INSERT INTO role_menu
VALUES
	( 2, 1 );
INSERT INTO role_menu
VALUES
	( 2, 2 );

添加依赖

<dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-security</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
 <scope>test</scope>
 </dependency>
 <!--mybatis-plus-->
 <dependency>
 <groupId>com.baomidou</groupId>
 <artifactId>mybatis-plus-boot-starter</artifactId>
 <version>3.5.0</version>
 </dependency>
 <!--mysql-->
 <dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 </dependency>
 <!--lombok 用来简化实体类-->
 <dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 </dependency>
</dependencies>

制作实体类 

@Data
public class Users {
 private Integer id;
 private String username;
 private String password;
}

整合 MybatisPlus 制作 mapper

@Repository
public interface UsersMapper extends BaseMapper<Users> {
}

制作登录实现类

/**
 * @author: haijin
 * @Date: 2022/11/06 16:00
 */
@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UsersMapper usersMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//        QueryWrapper<Users> wrapper = new QueryWrapper();
//        wrapper.eq("username",username);
//        Users users = usersMapper.selectOne(wrapper);
//        if(users == null) {
//            throw new UsernameNotFoundException("用户名不存在!");
//        }
        Users users = usersMapper.selectOne(Wrappers.<Users>lambdaQuery()
            .eq(Users::getUsername,username)
        );
        System.out.println(users);
        if(users == null) {
            throw new UsernameNotFoundException("用户名不存在!");
        }
        List<GrantedAuthority> auths =
                AuthorityUtils.commaSeparatedStringToAuthorityList("role");
//        new BCryptPasswordEncoder().encode(users.getPassword())
        return new User(users.getUsername(),
                users.getPassword(),auths);
    }

}

数据库连接:

#mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=liuhaijin

注入PasswordEncoder类到spring容器中

/**
 * @author: haijin
 * @Date: 2022/10/29 23:56
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsServiceImpl myUserDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() // 表单登录
                .and()
                .authorizeRequests() // 认证配置
                .anyRequest() // 任何请求
                .authenticated(); // 都需要身份验证
    }

    // 注入 PasswordEncoder 类到 spring 容器中
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

项目截图

3、未认证请求跳转到登录页

引入前端模板依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

编写未认证页面unauth.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>没有访问权限!</h1>
</body>
</html>

login.html

<!DOCTYPE html>
<!-- 需要添加
<html  xmlns:th="http://www.thymeleaf.org">
这样在后面的th标签就不会报错
 -->
<html  xmlns:th="http://www.thymeleaf.org">
<head lang="en">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>xx</title>
</head>
<body>


<h1>表单提交</h1>
<!-- 表单提交用户信息,注意字段的设置,直接是*{} -->
<form action="/user/login"  method="post">
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    <input type="text" name="username" />
    <input type="text" name="password" />
    <input type="submit" />
</form>
</body>
</html>

注意:页面提交方式必须为 post 请求,所以上面的页面不能使用,用户名,密码必须为
username,password

原因:
在执行登录的时候会走一个过滤器 UsernamePasswordAuthenticationFilter

如果修改配置可以调用 usernameParameter()和 passwordParameter()方法。

success.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    登录成功!
    <a href="/logout">退出</a>
</body>
</html>

将上面的文件放到resources/static中

编写控制器

/**
 * @author: haijin
 * @Date: 2022/10/30 0:14
 */
@Controller
public class IndexController {

    @GetMapping("login")
    public String login(){
        return "login";
    }

    @GetMapping("/")
    @ResponseBody
    public String index(){
        return "index";
    }

    @GetMapping("findAll")
    @ResponseBody
    public String findAll(){
        return "findAll";
    }

}

编写配置类放行登录页面以及静态资源 

/**
 * @author: haijin
 * @Date: 2022/10/29 23:56
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsServiceImpl myUserDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置没有权限访问跳转自定义页面
        http.exceptionHandling().accessDeniedPage("/unauth.html");
        // 配置认证
        http.formLogin()
                // 配置哪个 url 为登录页面
                .loginPage("/login.html")
                // 设置哪个是登录的 url。
                .loginProcessingUrl("/user/login")
                //登录成功之后,跳转路径
                .defaultSuccessUrl("/success.html").permitAll()
                // 登录失败之后,跳转的页面
                .failureUrl("/unauth.html")
                .permitAll()
                .and()
                .authorizeRequests()
                // 登录跳过页面
                .antMatchers("/user/login")
                // 指定 URL 无需保护。
                .permitAll()
                // 其他请求
                .anyRequest()
                .authenticated(); //需要认证
        // 关闭 csrf
        http.csrf().disable();

    }

    // 注入 PasswordEncoder 类到 spring 容器中
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

}

访问没有配置的路径就会被拦截

项目截图

 

 

 

 

 

 

你好:我的2025