链接上一篇文章: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();
}
}
访问没有配置的路径就会被拦截
项目截图