# success-yeb
**Repository Path**: guancg/success-yeb
## Basic Information
- **Project Name**: success-yeb
- **Description**: 架构前后端分离springboot+vue,涉及到的技术点
基于mysql8.x,mybatisplus3.x,springboot2.5.0,security,jwt,redis,rabbitMQ,websocket的前后端分离项目后台系统.供学习参考.如果需要数据库文件,请加849962874[QQ]
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 5
- **Forks**: 0
- **Created**: 2021-05-26
- **Last Updated**: 2022-03-06
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Mybatis-plus逆向工程
> 官网指南 - https://baomidou.com/guide/
>
> 逆向工程 - yeb-generator模块中
## 依赖
~~~xml
4.0.0
tech.aistar
yeb-demo
0.0.1-SNAPSHOT
tech.aistar
yeb-generator
0.0.1-SNAPSHOT
yeb-generator
Demo project for Spring Boot
1.8
org.freemarker
freemarker
com.baomidou
mybatis-plus-boot-starter
3.4.3
mysql
mysql-connector-java
runtime
com.baomidou
mybatis-plus-generator
3.4.1
io.springfox
springfox-boot-starter
3.0.0
org.projectlombok
lombok
true
com.github.xiaoymin
swagger-bootstrap-ui
1.9.6
org.springframework.boot
spring-boot-maven-plugin
~~~
## 配置类
> 完成之后执行main方法即可
~~~java
package tech.aistar.generator;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class CodeGenerator {
/**
*
* 读取控制台内容
*
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/yeb-generator/src/main/java");
gc.setAuthor("亲爱的小管");
// 打开输出目录
gc.setOpen(false);
// xml开启BaseResultMap
gc.setBaseResultMap(true);
// xml开启BaseColumnList
gc.setBaseColumnList(true);
//实体属性 Swagger2 注解
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/yeb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
// pc.setModuleName(scanner("模块名"));
pc.setParent("tech.aistar")
.setEntity("pojo")
.setMapper("mapper")
.setService("service")
.setServiceImpl("service.impl")
.setController("controller");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/yeb-generator/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录,自定义目录用");
if (fileType == FileType.MAPPER) {
// 已经生成 mapper 文件判断存在,不想重新生成返回 false
return !new File(filePath).exists();
}
// 允许生成模板文件
return true;
}
});
*/
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
// templateConfig.setController();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
// 数据库表映射到实体的命名策略
strategy.setNaming(NamingStrategy.underline_to_camel);
// 数据库表字段映射到实体的命名策略
strategy.setColumnNaming(NamingStrategy.no_change);
// strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
// lombok
strategy.setEntityLombokModel(true);
// 生产restController
strategy.setRestControllerStyle(true);
// 公共父类
// strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
// 写于父类中的公共字段
// strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix("t_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
~~~
# SpringSecurity简介
> Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
## 快速入门
> 1. 添加依赖
>
> ~~~xml
>
> org.springframework.boot
> spring-boot-starter-security
>
> ~~~
>
> 2. 在src/main/resources/static目录下创建Login.html文件
>
> 3. 随便在哪个控制器中编写,比如
>
> ~~~java
> @Controller
> @RequestMapping("/admin")
> public class AdminController {
>
> @GetMapping
> public String login(){
> return "login.html";
> }
> }
> ~~~
>
> 4. 观察控制台,会发生有一段密码
>
> ~~~cmd
> Using generated security password: 1d212a99-7c2f-4ec0-9095-19d74168f8ff
> ~~~
>
> 5. 此时启动项目工程:localhost:8081/admin,会弹出Spring-security默认的登录界面,用户名为user,密码为控制台生成的[上面]
>
> 6. 输入验证完毕之后,可以成功跳转到login.html
## Spring Security身份认证之UserDetailsService
> 之前我们采用了配置文件的方式从数据库中读取用户进行登录。虽然该方式的灵活性相较于静态账号密码的方式灵活了许多,但是将数据库的结构暴露在明显的位置上,绝对不是一个明智的做法。本文通过Java代码实现UserDetailsService接口来实现身份认证。
> ~~~java
> public interface UserDetailsService {
> UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
> }
> ~~~
>
> ~~~java
> public interface UserDetails extends Serializable {
> //权限信息
> Collection extends GrantedAuthority> getAuthorities();
> //密码
> String getPassword();
> //用户名
> String getUsername();
> //账户是否过期 true : 没有 false : 过期
> boolean isAccountNonExpired();
> //账户是否锁定<是否冻结> false : 冻结
> boolean isAccountNonLocked();
> //密码是否过期 true : 没有 false : 过期
> boolean isCredentialsNonExpired();
> //账户是否可用<用户是否删除>
> boolean isEnabled();
> }
> ~~~
## 权限认证模拟操作
> 1. 编写Security配置类:
>
> ~~~java
> package tech.aistar.config;
>
> import org.springframework.context.annotation.Bean;
> import org.springframework.context.annotation.Configuration;
> import org.springframework.security.config.annotation.web.builders.HttpSecurity;
> import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
> import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
>
> /**
> * 本类用来演示: SpringSecurity配置类
> *
> * @author: success
> * @date: 2021/5/26 6:59 下午
> */
> @Configuration
> public class SecurityConfig {
>
> @Bean
> public BCryptPasswordEncoder bCryptPasswordEncoder(){
> return new BCryptPasswordEncoder();
> }
> }
> ~~~
>
> 2. 编写认证逻辑
>
> ~~~java
> package tech.aistar.service.impl2;
>
> import org.springframework.beans.factory.annotation.Autowired;
> import org.springframework.security.core.authority.AuthorityUtils;
> import org.springframework.security.core.userdetails.User;
> import org.springframework.security.core.userdetails.UserDetails;
> import org.springframework.security.core.userdetails.UserDetailsService;
> import org.springframework.security.core.userdetails.UsernameNotFoundException;
> import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
> import org.springframework.stereotype.Service;
>
> /**
> * 本类用来演示: 自定义登录逻辑
> *
> * @author: success
> * @date: 2021/5/26 7:33 下午
> */
> @Service
> public class UserDetailsServiceImpl implements UserDetailsService {
>
> @Autowired
> private BCryptPasswordEncoder bCryptPasswordEncoder;
>
> /**
> *
> * @param username 必须要和登录表单控件的name属性值保持一致,都是username
> * @return
> * @throws UsernameNotFoundException
> */
> @Override
> public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
> //1、通过提供的用户名参数访问数据库,查询记录返回过来,如果记录不存在则抛出异常
> if(!"admin".equals(username)){
> throw new UsernameNotFoundException("用户名不存在!");
> }
> //2. 查询出来的凭证是被加密了的,这里是模拟查询的密码
> String password = bCryptPasswordEncoder.encode("123");
>
> //3.权限不可以为空,所以需要这么一个工具方法简单实现
> return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
> }
> }
> ~~~
>
> 3. 重启项目,localhost:8081/admin
>
> ~~~java
> 重启项目,登陆测试:
>
> 用户名称是admin,密码是123
>
> 填写的不是admin也一样报这个错误,但是控制台并没有抛出我们设置的异常(throw new UsernameNotFoundException("用户名不存在!");)
>
> 也就是说,UserDetails对象交给其他Security的方法来判断了
> ~~~
## 自定义登录界面
> 1. 自定义登录界面
>
> ~~~html
>
>
>
>
> Title
>
>
>
> custom login page
>
>
>
>
> ~~~
>
> `注意此处的name="ussername"的属性值username一定要和 loadUserByUsername(String username)方法的参数username保持一致,否则接受不到`
>
> 2. 在之前的Security配置类中增加这些配置:
>
> ~~~java
> package tech.aistar.config;
>
> import org.springframework.context.annotation.Bean;
> import org.springframework.context.annotation.Configuration;
> import org.springframework.security.config.annotation.web.builders.HttpSecurity;
> import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
> import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
>
> /**
> * 本类用来演示: SpringSecurity配置类
> *
> * @author: success
> * @date: 2021/5/26 6:59 下午
> */
> @Configuration
> public class SecurityConfig extends WebSecurityConfigurerAdapter{
> /**
> * 注意授权的请求处理,匹配的URL是重定向的地址,而不是控制器的URL。
> * @param http
> * @throws Exception
> */
> @Override
> protected void configure(HttpSecurity http) throws Exception {
> //设置登录行为为表单登录
> http.formLogin()
> .loginPage("/login.html")
> //此处的/login需要和表单的action的属性值保持一致
> .loginProcessingUrl("/login")
> //Security的失败页面跳转也是由配置Bean的方法决定的,请求方式是POST请求
> //所以这个登陆失败的页面跳转也需要一个控制器处理
> //登录成功跳转,post请求
> .successForwardUrl("/admin/main")
> //登录失败跳转,post请求
> .failureForwardUrl("/admin/error");
>
> //授权认证
> http.authorizeRequests()
> //设置登录页面允许访问
> .antMatchers("/login.html","/error.html").permitAll()
>
> //设置所有请求都要被认证
> .anyRequest().authenticated();
>
> // CSRF攻击拦截关闭
> http.csrf().disable();
> }
>
> @Bean
> public BCryptPasswordEncoder bCryptPasswordEncoder(){
> return new BCryptPasswordEncoder();
> }
> }
> ~~~
>
> 3. 修改控制器
>
> ~~~java
> package tech.aistar.controller;
>
>
> import org.springframework.stereotype.Controller;
> import org.springframework.web.bind.annotation.GetMapping;
> import org.springframework.web.bind.annotation.PostMapping;
> import org.springframework.web.bind.annotation.RequestMapping;
> import org.springframework.web.bind.annotation.RestController;
>
> /**
> *
> * 前端控制器
> *
> *
> * @author 亲爱的小管
> * @since 2021-05-26
> */
> @Controller
> @RequestMapping("/admin")
> public class AdminController {
>
> @GetMapping
> public String login(){
> return "login.html";
> }
>
> /**
> * 登录成功之后的跳转
> * @return
> */
> @PostMapping("/main")
> public String main(){
> System.out.println("main...");
> //此处只能重定向
> return "redirect:main.html";
> }
>
> @PostMapping("/error")
> public String error(){
> System.out.println("error...");
> return "redirect:error.html";
> }
> }
> ~~~
>
> 4. 在static目录下创建main.html和error.html - 内容随意,一个代表登录成功,一个代表登录失败
## 自定义请求账户和密码的别名
> 之前说过login的form表单提交必须是post请求,用户名必须是username,密码必须是password,为什么呢?原因是因为这个过滤器类:
>
> `org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter`
>
> ~~~java
> 代码片段:
> public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
> public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
>
> if (this.postOnly && !request.getMethod().equals("POST")) {
> throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
> }
> ~~~
> 如果要改变默认的请求参数,可以设置:
>
> 修改logjn.html
>
> ~~~html
> username:
> password:
> ~~~
>
> 修改SecurityConfig,加入俩段配置
>
> `usernameParameter("uname")`和`.passwordParameter("pwd")`
>
> ~~~java
> package tech.aistar.config;
>
> import org.springframework.context.annotation.Bean;
> import org.springframework.context.annotation.Configuration;
> import org.springframework.security.config.annotation.web.builders.HttpSecurity;
> import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
> import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
>
> /**
> * 本类用来演示: SpringSecurity配置类
> *
> * @author: success
> * @date: 2021/5/26 6:59 下午
> */
> @Configuration
> public class SecurityConfig extends WebSecurityConfigurerAdapter{
> /**
> * 注意授权的请求处理,匹配的URL是重定向的地址,而不是控制器的URL。
> * @param http
> * @throws Exception
> */
> @Override
> protected void configure(HttpSecurity http) throws Exception {
> //设置登录行为为表单登录
> http.formLogin()
> //自定义登录表单的用户名和密码的属性值
> .usernameParameter("uname")
> .passwordParameter("pwd")
> .loginPage("/login.html")
> //此处的/login需要和表单的action的属性值保持一致
> .loginProcessingUrl("/login")
> //Security的失败页面跳转也是由配置Bean的方法决定的,请求方式是POST请求
> //所以这个登陆失败的页面跳转也需要一个控制器处理
> //登录成功跳转,post请求
> .successForwardUrl("/admin/main")
> //登录失败跳转,post请求
> .failureForwardUrl("/admin/error");
>
> //授权认证
> http.authorizeRequests()
> //设置登录页面允许访问
> .antMatchers("/login.html","/error.html").permitAll()
>
> //设置所有请求都要被认证
> .anyRequest().authenticated();
>
> // CSRF攻击拦截关闭
> http.csrf().disable();
> }
>
> @Bean
> public BCryptPasswordEncoder bCryptPasswordEncoder(){
> return new BCryptPasswordEncoder();
> }
> }
>
> ~~~
## 自定义登录成功处理器
> 问题域:使用默认successForwardUrl并不能用来跳转到外部地址,也就是跨域访问
>
> 例如这样设置成功登陆页进行跳转:
>
> `successForwardUrl("http://www.baidu.com")`;//结果是跳转失败的,抛出404
> 分析successForwardUrl方法对应的源码,发现底层实际上是调用了successHandler方法
>
> ~~~java
> public FormLoginConfigurer successForwardUrl(String forwardUrl) {
> this.successHandler(new ForwardAuthenticationSuccessHandler(forwardUrl));
> return this;
> }
> ~~~
>
> 继续分析ForwardAuthenticationSuccessHandler源码
>
> ~~~java
> public class ForwardAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
> private final String forwardUrl;
>
> public ForwardAuthenticationSuccessHandler(String forwardUrl) {
> Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), () -> {
> return "'" + forwardUrl + "' is not a valid forward URL";
> });
> this.forwardUrl = forwardUrl;
> }
>
> public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
> // 此处实际上就是一个转发
> request.getRequestDispatcher(this.forwardUrl).forward(request, response);
> }
> }
> ~~~
### 实现步骤
> 编写一个自己的LoginSuccessHanlder去实现AuthenticationSuccessHandler接口
>
> ~~~java
> package tech.aistar.handler;
>
> import org.springframework.security.core.Authentication;
> import org.springframework.security.core.userdetails.User;
> import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
>
> import javax.servlet.ServletException;
> import javax.servlet.http.HttpServletRequest;
> import javax.servlet.http.HttpServletResponse;
> import java.io.IOException;
>
> /**
> * 本类用来演示: 登录成功跳转自定义处理器
> *
> * @author: success
> * @date: 2021/5/28 1:41 下午
> */
> public class LoginSuccessHandler implements AuthenticationSuccessHandler {
> private String url;
>
> public LoginSuccessHandler(String url){
> this.url = url;
> }
>
> @Override
> public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
> //此处可以获取登录的用户信息
> User user = (User) authentication.getPrincipal();
> System.out.println("user-username:"+user.getUsername());
> //出于安全性考虑,此处的密码应该是获取不到的
> System.out.println("user-password:"+user.getPassword());
> //获取权限
> System.out.println("user-authentication:"+user.getAuthorities());
>
> //重定向到自己的url
> httpServletResponse.sendRedirect(url);
> }
> }
> ~~~
>
> 修改SecurityConfig.java
>
> ` .successHandler(new LoginSuccessHandler("http://www.baidu.com"))`
>
> ~~~java
> package tech.aistar.config;
>
> import org.springframework.context.annotation.Bean;
> import org.springframework.context.annotation.Configuration;
> import org.springframework.security.config.annotation.web.builders.HttpSecurity;
> import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
> import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
> import tech.aistar.handler.LoginSuccessHandler;
>
> /**
> * 本类用来演示: SpringSecurity配置类
> *
> * @author: success
> * @date: 2021/5/26 6:59 下午
> */
> @Configuration
> public class SecurityConfig extends WebSecurityConfigurerAdapter{
> /**
> * 注意授权的请求处理,匹配的URL是重定向的地址,而不是控制器的URL。
> * @param http
> * @throws Exception
> */
> @Override
> protected void configure(HttpSecurity http) throws Exception {
> //设置登录行为为表单登录
> http.formLogin()
> //自定义登录表单的用户名和密码的属性值
> .usernameParameter("uname")
> .passwordParameter("pwd")
> .loginPage("/login.html")
> //此处的/login需要和表单的action的属性值保持一致
> .loginProcessingUrl("/login")
> //Security的失败页面跳转也是由配置Bean的方法决定的,请求方式是POST请求
> //所以这个登陆失败的页面跳转也需要一个控制器处理
> //登录成功跳转,post请求
> //.successForwardUrl("/admin/main")
>
> //使用默认successForwardUrl并不能用来跳转到外部地址,也就是跨域访问
> //例如这样设置成功登陆页进行跳转:
> //.successForwardUrl("http://www.baidu.com")
>
> //设置登录成功自定义处理器
> //注意successForwardUrl和successHandler是不能共存的
> .successHandler(new LoginSuccessHandler("http://www.baidu.com"))
>
> //登录失败跳转,post请求
> .failureForwardUrl("/admin/error");
>
> //授权认证
> http.authorizeRequests()
> //设置登录页面允许访问
> .antMatchers("/login.html","/error.html").permitAll()
>
> //设置所有请求都要被认证
> .anyRequest().authenticated();
>
> // CSRF攻击拦截关闭
> http.csrf().disable();
> }
>
> @Bean
> public BCryptPasswordEncoder bCryptPasswordEncoder(){
> return new BCryptPasswordEncoder();
> }
> }
> ~~~
## 自定义登录失败处理器
> 问题域同上,查看failureForwardUrl源码,发现底层实际上是调用了failureHandler方法
>
> ~~~java
> public FormLoginConfigurer failureForwardUrl(String forwardUrl) {
> this.failureHandler(new ForwardAuthenticationFailureHandler(forwardUrl));
> return this;
> }
> ~~~
>
> 继续查看ForwardAuthenticationFailureHandler对象源码
>
> ~~~
> package org.springframework.security.web.authentication;
>
> import java.io.IOException;
> import javax.servlet.ServletException;
> import javax.servlet.http.HttpServletRequest;
> import javax.servlet.http.HttpServletResponse;
> import org.springframework.security.core.AuthenticationException;
> import org.springframework.security.web.util.UrlUtils;
> import org.springframework.util.Assert;
>
> public class ForwardAuthenticationFailureHandler implements AuthenticationFailureHandler {
> private final String forwardUrl;
>
> public ForwardAuthenticationFailureHandler(String forwardUrl) {
> Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), () -> {
> return "'" + forwardUrl + "' is not a valid forward URL";
> });
> this.forwardUrl = forwardUrl;
> }
>
> public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
> request.setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception);
> request.getRequestDispatcher(this.forwardUrl).forward(request, response);
> }
> }
### 实现步骤
> 1. 编写一个自定义的登录失败处理器LoginFailureHandler,去实现AuthenticationFailureHandler接口
>
> ~~~java
> package tech.aistar.handler;
>
> import org.springframework.security.core.AuthenticationException;
> import org.springframework.security.web.authentication.AuthenticationFailureHandler;
>
> import javax.servlet.ServletException;
> import javax.servlet.http.HttpServletRequest;
> import javax.servlet.http.HttpServletResponse;
> import java.io.IOException;
>
> /**
> * 本类用来演示: 登录失败处理器
> *
> * @author: success
> * @date: 2021/5/28 1:59 下午
> */
> public class LoginFailureHandler implements AuthenticationFailureHandler {
> private String url;
>
> public LoginFailureHandler(String url){
> this.url = url;
> }
> @Override
> public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
> httpServletResponse.sendRedirect(url);
> }
> }
> ~~~
>
> 2. 修改SecurityConfig.java
>
> ` .failureHandler(new LoginFailureHandler("/error.html"));`
>
> ~~~java
> package tech.aistar.config;
>
> import org.springframework.context.annotation.Bean;
> import org.springframework.context.annotation.Configuration;
> import org.springframework.security.config.annotation.web.builders.HttpSecurity;
> import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
> import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
> import tech.aistar.handler.LoginFailureHandler;
> import tech.aistar.handler.LoginSuccessHandler;
>
> /**
> * 本类用来演示: SpringSecurity配置类
> *
> * @author: success
> * @date: 2021/5/26 6:59 下午
> */
> @Configuration
> public class SecurityConfig extends WebSecurityConfigurerAdapter{
> /**
> * 注意授权的请求处理,匹配的URL是重定向的地址,而不是控制器的URL。
> * @param http
> * @throws Exception
> */
> @Override
> protected void configure(HttpSecurity http) throws Exception {
> //设置登录行为为表单登录
> http.formLogin()
> //自定义登录表单的用户名和密码的属性值
> .usernameParameter("uname")
> .passwordParameter("pwd")
> .loginPage("/login.html")
> //此处的/login需要和表单的action的属性值保持一致
> .loginProcessingUrl("/login")
> //Security的失败页面跳转也是由配置Bean的方法决定的,请求方式是POST请求
> //所以这个登陆失败的页面跳转也需要一个控制器处理
> //登录成功跳转,post请求
> //.successForwardUrl("/admin/main")
>
> //使用默认successForwardUrl并不能用来跳转到外部地址,也就是跨域访问
> //例如这样设置成功登陆页进行跳转:
> //.successForwardUrl("http://www.baidu.com")
>
> //设置登录成功自定义处理器
> //注意successForwardUrl和successHandler是不能共存的
> .successHandler(new LoginSuccessHandler("http://www.baidu.com"))
>
> //登录失败跳转,post请求
> //.failureForwardUrl("/admin/error");
>
> //自定义登录失败处理器
> .failureHandler(new LoginFailureHandler("/error.html"));
>
> //授权认证
> http.authorizeRequests()
> //设置登录页面允许访问
> .antMatchers("/login.html","/error.html").permitAll()
>
> //设置所有请求都要被认证
> .anyRequest().authenticated();
>
> // CSRF攻击拦截关闭
> http.csrf().disable();
> }
>
> @Bean
> public BCryptPasswordEncoder bCryptPasswordEncoder(){
> return new BCryptPasswordEncoder();
> }
> }
> ~~~
## antMatchers参数讲解
> ~~~java
> public C antMatchers(String... antPatterns) {..}
> ~~~
>
> 参数是不定向参数,每个参数都是一个ant表达式,用于匹配url规则,规则如下:
> 1. ? 匹配任意单个字符
> 2. *匹配0或者任意数量的字符
> 3. ** 匹配0或者更多的目录
`在实际项目中经常需要放行所有的静态资源,下面演示js文件夹下所有的js脚本文件`
~~~java
.antMatchers("/js/**","/css/**").permitAll();
~~~
`另外一种方式`
~~~java
.antMachers("/**/*.js","/**/*.css").permitAll();
~~~
## 如果项目中添加了context-path
> 修改login.html的action="/yeb/login"
>
> 修改配置类
>
> ~~~java
> package tech.aistar.config;
>
> import org.springframework.context.annotation.Bean;
> import org.springframework.context.annotation.Configuration;
> import org.springframework.security.config.annotation.web.builders.HttpSecurity;
> import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
> import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
> import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
> import tech.aistar.handler.LoginFailureHandler;
> import tech.aistar.handler.LoginSuccessHandler;
>
> /**
> * 本类用来演示: SpringSecurity配置类
> *
> * @author: success
> * @date: 2021/5/26 6:59 下午
> */
> @Configuration
> @EnableWebSecurity
> public class SecurityConfig extends WebSecurityConfigurerAdapter{
> /**
> * 注意授权的请求处理,匹配的URL是重定向的地址,而不是控制器的URL。
> * @param http
> * @throws Exception
> */
> @Override
> protected void configure(HttpSecurity http) throws Exception {
> //设置登录行为为表单登录
> http.formLogin()
> //自定义登录表单的用户名和密码的属性值
> .usernameParameter("uname")
> .passwordParameter("pwd")
> .loginPage("/login.html")
> //此处的/login需要和表单的action的属性值保持一致
> //此处如果配置了上下文路径,这里是不需要加上/yeb
> .loginProcessingUrl("/login")
> //Security的失败页面跳转也是由配置Bean的方法决定的,请求方式是POST请求
> //所以这个登陆失败的页面跳转也需要一个控制器处理
> //登录成功跳转,post请求
> //.successForwardUrl("/admin/main")
>
> //使用默认successForwardUrl并不能用来跳转到外部地址,也就是跨域访问
> //例如这样设置成功登陆页进行跳转:
> //.successForwardUrl("http://www.baidu.com")
>
> //设置登录成功自定义处理器
> //注意successForwardUrl和successHandler是不能共存的
> //.successHandler(new LoginSuccessHandler("http://www.baidu.com"))
> .successHandler(new LoginSuccessHandler("/yeb/main.html"))
>
> //登录失败跳转,post请求
> //.failureForwardUrl("/admin/error");
>
> //自定义登录失败处理器
> .failureHandler(new LoginFailureHandler("/yeb/error.html"));
>
> //授权认证
> http.authorizeRequests()
> //设置登录页面允许访问
> .antMatchers("/login.html","/error.html").permitAll()
>
> //设置所有请求都要被认证
> .anyRequest().authenticated();
>
> // CSRF攻击拦截关闭
> http.csrf().disable();
> }
>
> @Bean
> public BCryptPasswordEncoder bCryptPasswordEncoder(){
> return new BCryptPasswordEncoder();
> }
> }
> ~~~
## 内置访问控制方法及控制项
> ~~~java
> public final class ExpressionUrlAuthorizationConfigurer> extends AbstractInterceptUrlConfigurer, H> {
> static final String permitAll = "permitAll";
> private static final String denyAll = "denyAll";
> private static final String anonymous = "anonymous";
> private static final String authenticated = "authenticated";
> private static final String fullyAuthenticated = "fullyAuthenticated";
> private static final String rememberMe = "rememberMe";
> }
> ~~~
>
> > ```
> > 1. 全部允许 PermiAll
> > 2. 全部拒绝 DenyAll
> > 3. 允许匿名访问 Anonymous 也就是普通访问者
> > 4. 允许认证之后访问 Authenticated
> > 5. 必须完全认证? FullAuthenticated
> > 6. 记住我 RememberMe
> > ```