目录
一.简介
1.概括
2.历史
二.第一个 Spring Security 项目
创建项目
1.导入依赖
去查找依赖,注意父依赖的外层标签是<parent></parent>
pom.xml里配置
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
2.访问页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
main.html
</body>
</html>
LoginController.java:
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(){
System.out.println("执行了login方法");
return "redirect:main.html";
}
}
编写启动类:
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class);
}
}
在浏览器输入:http://localhost:8080/login.html 后会显示下面页面
但是咱们自己写的login.html没这么花哨啊,这是为啥呢?因为这是Spring Security帮我们设置的一个页面,默认Username是user,Password是在控制台的输出里
红线处就是生成的密码,每个人的都不一样。
填写登入之后会进入咱们自己写的login.html
三.UserDetailsService 详解
2.方法参数
3.异常
UsernameNotFoundException 用 户 名 没 有 发 现 异 常 。 在loadUserByUsername 中是需要通过自己的逻辑从数据库中取值的。如果 通 过 用 户 名 没 有 查 询 到 对 应 的 数 据 , 应 该 抛 出
四.PasswordEncoder 密码解析器详解
3.BCryptPasswordEncoder 简介
4.代码演示
@SpringBootTest
@RunWith(SpringRunner.class)
public class MyTest {
@Test
public void test(){
PasswordEncoder pe = new BCryptPasswordEncoder();
//对123进行加密
String encode = pe.encode("123");
System.out.println(encode);
//看加密后的密码和1234是否能匹配上,输出肯定是false,因为事和123匹配的
boolean matches = pe.matches("1234", encode);
System.out.println("============:"+matches);
}
}
控制台输出如下:
$2a$10$I3Gh5TQGNN/k3M7KE043fuGWcFNOshmyDviJlTY7jxl0wfHKp6jka
============:false
五.自定义登录逻辑
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder getPwdEncoder(){
return new BCryptPasswordEncoder();
}
}
2.自定义逻辑
下的函数设置登录用户名为admin,密码为123
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private PasswordEncoder encoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//登陆时就会用到这个类,就会输出下面这句话
System.out.println("执行了UserDetailsServiceImpl");
//1. 查询数据库判断用户名是否存在,如果不存在抛出UsernameNotFoundException
if(!username.equals("admin")){
throw new UsernameNotFoundException("用户名不存在");
}
//把查询出来的密码进行解析,或直接把password放到构造方法中。
//理解:password就是数据库中查询出来的密码,查询出来的内容不是123
String password = encoder.encode("123");
return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
启动项目时,注意运行的是哪个类,应该是启动类
访问localhost:8080/login.html
六.自定义登录页面
1.编写登录页面
- successForwardUrl()登录成功后跳转地址
- loginPage() 登录页面
- loginProcessingUrl 登录页面表单提交地址,此地址可以不真实存在。
- antMatchers():匹配内容
- permitAll():允许
只有配置了loginProcessingUrl和之后关闭csrf防护之后,登录时才会成功调用UserDetailsService接口的实现类,故而控制台才会输出UserDetailsServiceImpl类的控制台输出语句的值。
但是在登录界面输入用户名和密码却出现了下面的错误,所以还需要在进行successForwardUrl
配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder getPwdEncoder(){
return new BCryptPasswordEncoder();
}
protected void configure(HttpSecurity http) throws Exception{
//表单认证
http.formLogin()
/*设置登陆界面,这样访问localhost:8080/login.html时会直接跳转,
而不会先出现Spring Security的默认页面,但是你会发现http://localhost:8080/main.html也可以访问了,
所以这样就把所有拦截都取消了
*/
.loginPage("/login.html")
//当发现/login 时认为是登录,需要执行 UserDetailsServiceImpl
.loginProcessingUrl("/login")
//设置登录成功之后的跳转页面,为什么不直接写main.html,因为这个是post请求,而main.html是静态资源
.successForwardUrl("/toMain");
//url拦截
http.authorizeRequests()
//login.html 不需要被认证
.antMatchers("/login.html").permitAll()
//所有的请求都必须被认证。必须登录 后才能访问。
.anyRequest().authenticated();
//关闭 csrf 防护
http.csrf().disable();
}
}
3.编写控制器
@Controller
public class LoginController {
/*有没有这个都无所谓,因为这个路径实际上是不走的,login.html的action属性是/login只是为了
配置配置类里的loginProcessingUrl属性,使之对应起来而已
*/
// @RequestMapping("/login")
// public String login(){
// System.out.println("执行了login方法");
// return "redirect:main.html";
// }
@PostMapping("/toMain")
public String toMain(){
return "redirect:/main.html";
}
}
localhost:8080/login.html
输入用户名admin,密码123
七.认证过程其他常用配置
1.失败跳转
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
登陆失败,请重新登录。<a href="/login.html">跳转</a>
</body>
</html>
1.2修改表单配置
//登录失败跳转地址,因为这里仍然是post请求,所以还要对此路径写一个控制器
.failureForwardUrl("/fail")
1.3添加控制器方法
@PostMapping("/fail")
public String fail(){
return "redirect:/fail.html";
}
1.4设置 fail.html 不需要认证
运行项目,访问登录页面,故意写错用户名或密码,会跳转到fail.html,
点一下跳转就又回到了登录界面。
2.设置请求账户和密码的参数名
- usernamePasrameter:账户参数名(源码中规定了账户参数名必须是username)
- passwordParameter:密码参数名(源码中规定了密码参数名必须是password)
- postOnly=true:默认情况下只允许 POST 请求。
注意登录页面的前端代码中的用户名和密码标签的name也得和 usernamePasrameter以及passwordParameter规定的值一样才行。
2.2修改配置
我需要在配置类里对usernamePasramete和passwordParameter进行修改,
例如我现在修改前端代码为:前面都加了个my
3.自定义登录成功处理器
当需要控制登录成功后去做一些事情时,可以进行自定义认证成功控制器。
我们现在以登陆成功之后跳转到百度为例演示以下,请看下面的代码实现。
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private String url;
public MyAuthenticationSuccessHandler(String url) {
this.url = url;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//Principal 主体,存放了登录用户的信息
User user = (User)authentication.getPrincipal();
System.out.println(user.getUsername());
//密码输出为 null
System.out.println(user.getPassword());
//System.out.println(user.getAuthorities());
//上面的代码是为了看一下getPrincipal能获得什么,而下面的代码是本小节的功能代码
response.sendRedirect(url);
}
}
//站外跳转,这个和successForwardUrl只能使用其一
.successHandler(new MyAuthenticationSuccessHandler("http://www.baidu.com"));
启动项目,访问localhost:8080/login.html
输入正确的用户名和密码之后,就会跳转到百度主页。
4. 自定义登录失败处理器
public class MyForwardAuthenticationFailureHandler implements AuthenticationFailureHandler {
private String url;
public MyForwardAuthenticationFailureHandler(String url) {
this.url = url;
}
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.sendRedirect("/fail.html");
}
}
启动项目自己故意输错用户名或密码测试一下。