springSecurity02mybatisspringmvcspring-01

32次阅读

共计 23520 个字符,预计需要花费 59 分钟才能阅读完成。

1. 建立一个模块继承上一个模块然后添加依赖

  <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.4</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.8</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.41</version>
        </dependency>
    </dependencies>
  
    <!-- 解决打包时找不到 xml 文件 -->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

2. 建立数据源文件 application.properties

# 数据库连接相关
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/security-demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username = root
jdbc.password = 123456

3. 修改 applicationContext.xml, 配置数据源, 和 mybatis 整合,以及事务管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.alibaba.com/schema/stat"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.alibaba.com/schema/stat http://www.alibaba.com/schema/stat.xsd">

    <!-- 自动扫描 -->
    <context:component-scan base-package="com.ty">
        <!-- 扫描时跳过 @TestController 注解的 JAVA 类(控制器)-->
        <context:exclude-filter type="annotation"
                                expression="org.springframework.stereotype.Controller" />
        <context:exclude-filter type="annotation"
                                expression="org.springframework.web.bind.annotation.ControllerAdvice" />
    </context:component-scan>

    <!-- 扫描配置文件(这里指向的是之前配置的那个 config.properties) -->
    <context:property-placeholder location="classpath:application.properties" />

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}" />  <!-- 数据库连接驱动 -->
        <property name="url" value="${jdbc.url}" />     <!-- 数据库地址 -->
        <property name="username" value="${jdbc.username}" />   <!-- 用户名 -->
        <property name="password" value="${jdbc.password}" />   <!-- 密码 -->
        <property name="maxActive" value="40" />      <!-- 最大连接数 -->
        <property name="minIdle" value="1" />       <!-- 最小连接数 -->
        <property name="initialSize" value="10" />      <!-- 初始化连接池内的数据库连接 -->
        <property name="maxWait" value="20" />  <!-- 最大空闲时间 -->
    </bean>

    <!--mybatis 与 spring 整合 -->
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 配置别名扫描包 -->
        <property name="typeAliasesPackage" value="com.ty.pojo"></property>
        <property name="mapperLocations" value="classpath:com.ty.mapper/*.xml"></property>
    </bean>

    <!-- 扫描接口 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.ty.mapper"></property>
    </bean>

   <!-- 事务配置 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 开启事务 -->
    <tx:annotation-drive
![图片上传中...]
n/>

</beans>

目录结构, 我这里测试 mybatis 时放在同一包出问题, 所以选择了分别扫描 xml 和 mapper 接口

数据库,总共建立了 5 张表, 用户表,角色表, 用户角色对应表, 权限表, 权限角色对应表, 关系也很简单, 一个用户有多个角色, 一个角色也可以有多个用户拥有, 一个角色有多种权限, 一个权限也可以由多个角色掌握, 这个看自己怎么设计, 其中用户表最重要, 这里面包含了用户的基本信息

/*
Navicat MySQL Data Transfer

Source Server         : security
Source Server Version : 50719
Source Host           : localhost:3306
Source Database       : security-demo

Target Server Type    : MYSQL
Target Server Version : 50719
File Encoding         : 65001

Date: 2019-08-02 10:25:48
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for sys_authorization
-- ----------------------------
DROP TABLE IF EXISTS `sys_authorization`;
CREATE TABLE `sys_authorization` (`id` int(11) NOT NULL,
  `authorizationName` varchar(50) DEFAULT NULL,
  `authorizationMark` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_authorization
-- ----------------------------
INSERT INTO `sys_authorization` VALUES ('1', '产品查询', 'ROLE_LIST_PRODUCT');
INSERT INTO `sys_authorization` VALUES ('2', '产品添加', 'ROLE_ADD_PRODUCT');
INSERT INTO `sys_authorization` VALUES ('3', '产品修改', 'ROLE_UPDATE_PRODUCT');
INSERT INTO `sys_authorization` VALUES ('4', '产品删除', 'ROLE_DELETE_PRODUCT');

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (`id` int(11) NOT NULL,
  `roleName` varchar(50) DEFAULT NULL,
  `roleDescription` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', '普通用户', '普通用户');
INSERT INTO `sys_role` VALUES ('2', '管理员', '管理员');

-- ----------------------------
-- Table structure for sys_role_authorization
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_authorization`;
CREATE TABLE `sys_role_authorization` (`roleId` int(11) NOT NULL,
  `authorizationId` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_role_authorization
-- ----------------------------
INSERT INTO `sys_role_authorization` VALUES ('1', '1');
INSERT INTO `sys_role_authorization` VALUES ('1', '2');
INSERT INTO `sys_role_authorization` VALUES ('2', '1');
INSERT INTO `sys_role_authorization` VALUES ('2', '2');
INSERT INTO `sys_role_authorization` VALUES ('2', '3');
INSERT INTO `sys_role_authorization` VALUES ('2', '4');

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (`id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL,
  `realname` varchar(50) DEFAULT NULL,
  `createDate` date DEFAULT NULL,
  `lastLoginTime` date DEFAULT NULL,
  `enabled` int(11) DEFAULT NULL,
  `accountNonExpired` int(11) DEFAULT NULL,
  `accountNonLocked` int(11) DEFAULT NULL,
  `credentialsNonExpired` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'jojo', '$2a$10$VCvgzml/DNzBTkjsPlImDuZp38sNZB7cEmsNgFIWBm/Vtpn0Q3Bj.', '张三', '2019-06-26', '2019-08-01', '1', '1', '1', '1');
INSERT INTO `sys_user` VALUES ('2', 'jack', '$2a$10$W1T2Z5dUMIgBfxvFdBOWuusq8Nwke/cQydxDFemsbTh0PjGeZCiMC', '李四', '2019-07-30', '2019-08-01', '1', '1', '1', '1');

-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (`userId` int(11) NOT NULL,
  `roleId` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES ('1', '1');
INSERT INTO `sys_user_role` VALUES ('2', '2');

基本配置完成
在 mapper 文件夹下建立 UserMapper 接口

package com.ty.mapper;

import com.ty.pojo.Authorization;
import com.ty.pojo.User;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

/**
 * @Author:TY
 * @Descroption:
 * @Date: Created in 11:34 2019/8/1
 * @Modificd By:
 */
public interface UserMapper {@Select("select * from sys_user")
    List<User> findAll();
    /**
     * 查询当前用户对象
     */

    public User findByUserName(String username);


    /**
     * 查询当前用户的权限
     */
    List<Authorization> findAuthorizationByUserName(String username);

    /**
     * 修改密码
     */

    @Update("update sys_user set password=#{password} where username=#{username}")
    public void updatePassword(User user);


}

UserMapper.xml:

<?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.ty.mapper.UserMapper">


    <select id="findByUserName" resultType="User" parameterType="String">
         SELECT * FROM sys_user where username = #{username}
    </select>


    <select id="findAuthorizationByUserName" parameterType="String" resultType="Authorization">
          SELECT a.* from sys_user u ,sys_user_role ur,sys_role_authorization ra,sys_authorization a
          WHERE u.id=ur.userId  and ur.roleId= ra.roleId and ra.authorizationId=a.id
          AND u.username=#{username}
    </select>
</mapper>

想要测试就这样


在 MainController 里面添加一个验证码接口(生成验证码网上都有, 这里就不列出了)

    @RequestMapping("/imageCode")
    public void imageCode(HttpServletRequest request, HttpServletResponse response) throws Exception {//        ImageCodeProcessor.send(new ServletWebRequest(request,response),new ImageCodeGenerator().generate(new ServletWebRequest(request)));
        ImageCode generate = new ImageCodeGenerator().generate(new ServletWebRequest(request));
        HttpSession session = request.getSession();
        System.out.println("生成的验证码为:"+generate.getCode());
        session.setAttribute("key",generate.getCode());
        response.setContentType("image/jpeg");
        // 将图像输出到 Servlet 输出流中。ServletOutputStream sos = response.getOutputStream();
        ImageIO.write(generate.getImage(), "jpeg", sos);
        sos.close();}

pojo 包中的 User 对象,里面添加了一个权限的字段,是 user 表中没有的, 并且 User 对象实现了 UserDetails 接口, 实现了其中的方法,方便后面 security 使用

package com.ty.pojo;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class User implements UserDetails{

  private Integer id;
  private String username;
  private String password;
  private String realname;
  private java.util.Date createDate;
  private java.util.Date lastLoginTime;
  private boolean enabled;
  private boolean accountNonExpired;
  private boolean accountNonLocked;
  private boolean credentialsNonExpired;

  // 用户拥有的所有权限
  List<GrantedAuthority>  authorities=new ArrayList<>();

  @Override
  public String toString() {
    return "User{" +
            "username='" + username + '\'' +
            ", realname='" + realname + '\'' +
            ", authorities=" + authorities +
            '}';
  }

  @Override
  public String getPassword() {return password;}

  public void setPassword(String password) {this.password = password;}

  public List<GrantedAuthority> getAuthorities() {return authorities;}



  public void setAuthorities(List<GrantedAuthority> authorities) {this.authorities = authorities;}

  public Integer getId() {return id;}

  public void setId(Integer id) {this.id = id;}

  public String getUsername() {return username;}

  public void setUsername(String username) {this.username = username;}

  public String getRealname() {return realname;}

  public void setRealname(String realname) {this.realname = realname;}

  public Date getCreateDate() {return createDate;}

  public void setCreateDate(Date createDate) {this.createDate = createDate;}

  public Date getLastLoginTime() {return lastLoginTime;}

  public void setLastLoginTime(Date lastLoginTime) {this.lastLoginTime = lastLoginTime;}

  public boolean isEnabled() {return enabled;}

  public void setEnabled(boolean enabled) {this.enabled = enabled;}

  public boolean isAccountNonExpired() {return accountNonExpired;}

  public void setAccountNonExpired(boolean accountNonExpired) {this.accountNonExpired = accountNonExpired;}

  public boolean isAccountNonLocked() {return accountNonLocked;}

  public void setAccountNonLocked(boolean accountNonLocked) {this.accountNonLocked = accountNonLocked;}

  public boolean isCredentialsNonExpired() {return credentialsNonExpired;}

  public void setCredentialsNonExpired(boolean credentialsNonExpired) {this.credentialsNonExpired = credentialsNonExpired;}
}

其它表就直接用 idea 自带的工具: 数据库生成 pojo 类执行就行了

连接数据库点击

springSecurity.xml: 里面都有注释, 而且也不难, 一看就会系列

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security-4.2.xsd">
    <!--  <security:http>: 对 web.xml 中 spring 过滤器链的配置:web.xml 里面的过滤器接受到请求, 就会根据这个配置去过滤
    1)需要拦截什么资源
    2)什么资源什么角色权限
    3)定义认证方式:HttpBasic,FormLogin
    4)定义登陆页面,定义登陆请求地址, 定义错误处理方式
    用于授权
    -->
    <security:http>
        <security:intercept-url pattern="/product/index" access="permitAll()"></security:intercept-url>
        <security:intercept-url pattern="/product/list" access="hasAuthority('ROLE_LIST_PRODUCT')"></security:intercept-url>
        <security:intercept-url pattern="/product/add" access="hasAuthority('ROLE_ADD_PRODUCT')"></security:intercept-url>
        <security:intercept-url pattern="/product/update" access="hasAuthority('ROLE_UPDATE_PRODUCT')"></security:intercept-url>
        <security:intercept-url pattern="/product/delete" access="hasAuthority('ROLE_DELETE_PRODUCT')"></security:intercept-url>
        <security:intercept-url pattern="/js/**" access="permitAll()"></security:intercept-url>

        <security:intercept-url pattern="/imageCode" access="permitAll()"></security:intercept-url>

        <security:intercept-url pattern="/userLogin" access="permitAll()"></security:intercept-url>
        <security:intercept-url pattern="/**" access="isFullyAuthenticated()"></security:intercept-url>



        <!-- 自定义 SpringSecurity 过滤器 -->
        <security:custom-filter ref="imageCodeAuthenticationFilter" before="FORM_LOGIN_FILTER"/>

        <security:form-login login-page="/userLogin" login-processing-url="/login"
                             authentication-success-handler-ref="mySuccessAthenticationHandler"
                            authentication-failure-handler-ref="myAuthenticationFailureHandler"/>


        <!-- 权限不足做处理 -->
        <security:access-denied-handler error-page="/error"></security:access-denied-handler>
        <security:csrf disabled="true"></security:csrf>

        <!-- 加上 rememberme 的功能 -->
        <!--token-validity-seconds:cookie 过期时间 -->
        <security:remember-me token-repository-ref="jdbcTokenRepository" token-validity-seconds="3600"></security:remember-me>
    </security:http>

    <security:authentication-manager>
        <security:authentication-provider user-service-ref="myUserDetailService">
            <!-- 使用加密的算法, 然后再和数据库密码配对 -->
            <security:password-encoder ref="passwordEncoder"></security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>


    <bean id="imageCodeAuthenticationFilter" class="com.ty.security.ImageCodeAuthenticationFilter">
        <property name="authenticationFailureHandler" ref="myAuthenticationFailureHandler"></property>
    </bean>

    <bean id="myUserDetailService" class="com.ty.security.MyUserDetailService"></bean>
    <bean id="mySuccessAthenticationHandler" class="com.ty.security.MySuccessAthenticationHandler"></bean>

    <!-- 失败处理器 -->
    <bean id="myAuthenticationFailureHandler" class="com.ty.security.MyAuthenticationFailureHandler"></bean>

    <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>


    <!--rememberme 功能的 bean-->
    <bean id="jdbcTokenRepository" class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
        <property name="dataSource" ref="dataSource"></property>
        <!-- 启动的时候生成表 persistent_logins, 但是有的话一定要把数据库的表删掉或者把这个注释掉 -->
        <!--<property name="createTableOnStartup" value="true"></property>-->
    </bean>
</beans>

MyUserDetailService : 这里就动态在数据库里面动态查询了用户的权限, 然后因为之前我们的 User 类实现了 UserDetails 接口, 所以当返回我们自己从数据库查询的用户然后返回的时候,springSecurity 会自己拿着用户输入的信息和我们数据库中的做一个比对, 对比上了则认证成功

package com.ty.security;

import com.ty.mapper.UserMapper;
import com.ty.pojo.Authorization;
import com.ty.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author:TY
 * @Descroption:
 * @Date: Created in 17:09 2019/8/1
 * @Modificd By:
 */
public class MyUserDetailService implements UserDetailsService{
    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user=null;
        System.out.println(username);
        if(username!=null&&!username.equals(""))
        {user = userMapper.findByUserName(username);
            if (user!=null)
            {
                // 获取用户权限
                List<Authorization>  permList = userMapper.findAuthorizationByUserName(username);
                List<GrantedAuthority> authorizations=new ArrayList<>();
                for (Authorization perm:permList)
                {GrantedAuthority authority=new SimpleGrantedAuthority(perm.getAuthorizationMark());
                     authorizations.add(authority);
                }
                user.setAuthorities(authorizations);
            }
            return user;
        }

        return user;
    }

}

然后我们自定义成功后的处理器 MySuccessAthenticationHandler

package com.ty.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
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;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author:TY
 * @Descroption:
 * @Date: Created in 19:43 2019/8/1
 * @Modificd By:
 */
public class MySuccessAthenticationHandler implements AuthenticationSuccessHandler {private static final ObjectMapper objectMapper=new ObjectMapper();
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {Map map=new HashMap();
        map.put("success",true);
        String result = objectMapper.writeValueAsString(map);
        httpServletResponse.setContentType("text/json;charset=utf-8");
        httpServletResponse.getWriter().write(result);
    }
}

失败处理器:

package com.ty.security;

import com.fasterxml.jackson.databind.ObjectMapper;
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;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author:TY
 * @Descroption:
 * @Date: Created in 21:23 2019/7/31
 * @Modificd By:
 */
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler{private    ObjectMapper objectMapper=new ObjectMapper();
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {Map map=new HashMap();
        map.put("success",false);
        map.put("errorMsg",e.getMessage());
        String result = objectMapper.writeValueAsString(map);
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write(result);
    }
}

登录的时候是先验证验证码, 验证码通过在验证用户名和密码
验证码的拦截器

package com.ty.security;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @Author:TY
 * @Descroption:,他能够确保在一次请求只通过一次 filter,而不需要重复执行
 *
 * @Date: Created in 21:22 2019/8/1
 * @Modificd By:
 */
public class ImageCodeAuthenticationFilter extends OncePerRequestFilter {

    private AuthenticationFailureHandler authenticationFailureHandler;


    public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {this.authenticationFailureHandler = authenticationFailureHandler;}

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        // 判断当前请求, 是否为登录请求,
        if (request.getRequestURI().contains("/login"))
        {
           try {
               // 校验验证码
               // 表单填的验证码
               String imageCode = request.getParameter("imageCode");
               System.out.println("表单填的验证码为:"+imageCode);
               // 系统生成的验证码
               HttpSession session = request.getSession();
               String  sesstionCode = (String) session.getAttribute("key");
               System.out.println("session 里的验证码为:"+sesstionCode);
               if(imageCode==null||imageCode.equals(""))
               {throw new ImageCodeException("验证码不能为空");
               }
               if(!imageCode.equals(sesstionCode))
               {throw new ImageCodeException("验证码错误");
               }
           }catch (AuthenticationException e){
             // 交给自定义的
               authenticationFailureHandler.onAuthenticationFailure(request,response,e);
               return;
           }
        }
        filterChain.doFilter(request,response);
    }
}

验证码异常类

package com.ty.security;


import org.springframework.security.core.AuthenticationException;

/**
 * @Author:TY
 * @Descroption:
 * @Date: Created in 21:47 2019/8/1
 * @Modificd By:
 */
public class ImageCodeException extends AuthenticationException {public ImageCodeException(String msg, Throwable t) {super(msg, t);
    }

    public ImageCodeException(String msg) {super(msg);
    }
}

注意: 我们是把验证码过滤器加在 UserNamePasswordAuthenticationFilter 前面的, 当我们的验证码抛出异常,验证码没通过时会抛一个 ImageCodeException, 这个类继承了 AuthenticationException , 所以当抛出异常之后会到我们自定义的 MyAuthenticationFailureHandler, 这样就可以向前端返回异常的数据

login.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
  Created by IntelliJ IDEA.
  User: TY
  Date: 2019/7/31
  Time: 19:14
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title> 登录页面 </title>
</head>
<body>
<c:if test="${not empty param.error}">
    <font color="red"> 用户名或密码错误 </font>
</c:if>
<form id="loginForm">
    用户名:<input type="text" name="username"><br>
    密 &ensp; 码:<input type="password" name="password"><br>
    验证码:<input type="text" name="imageCode"><img id="imgcheck" src="/imageCode"><br>
    <input type="checkbox" name="remember-me" value="true"> 记住我
    <input type="button" id="LoginButton" value="登录">
</form>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
<script type="text/javascript">
    $(function () {$("#LoginButton").click(function () {$.post("/login", $("#loginForm").serialize(), function (data) {if (data.success) {window.location.href = "${pageContext.request.contextPath}/product/index";
                } else {alert("登录失败:" + data.errorMsg);
                }
            }, "json");
        })
    })
    window.onload = function () {var date = new Date();
        $("#imgcheck").click(function () {$(this).attr('src', "/imageCode?temp=" + date);
        });
    }
</script>

</body>
</html>

如果要根据权限显示前端内容,就在 pom.xml 引入

    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-taglibs</artifactId>
      <version>4.2.3.RELEASE</version>
    </dependency>

index.jsp

<%--
  Created by IntelliJ IDEA.
  User: TY
  Date: 2019/7/31
  Time: 16:49
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title> 首页 </title>
</head>
<body>
<c:if test="${username != null}">
    <span> 欢迎 ${username}登陆 </span>
</c:if>
以下是网站的功能
<security:authorize access="hasAuthority('ROLE_ADD_PRODUCT')">
    <a href="/product/add"> 商品添加 </a>
</security:authorize>
<security:authorize access="hasAuthority('ROLE_UPDATE_PRODUCT')">
    <a href="/product/update"> 商品修改 </a>
</security:authorize>
<security:authorize access="hasAuthority('ROLE_LIST_PRODUCT')">
    <a href="/product/list"> 商品查询 </a>
</security:authorize>

<security:authorize access="hasAuthority('ROLE_DELETE_PRODUCT')">
    <a href="/product/delete"> 商品删除 </a>
</security:authorize>
</body>
</html>

** 最后如果想要获取认证通过后的用户的信息, 任何地方都能获取
可以使用 SecurityContextHolder.getContext().getAuthentication().getPrincipal()

    /**
     * 首页  SecurityContextHolder.getContext().getAuthentication().getPrincipal()可以在任何地方获取当前用户的信息
     */
    @RequestMapping("index")
    public String index(Model model)
    {Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if(principal!=null)
        {if(principal instanceof UserDetails)
            {UserDetails userDetails= (UserDetails)principal;
               model.addAttribute("username",userDetails.getUsername());
            }
        }
        return "index";
    }

**

正文完
 0