SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)

目录

前言

实战开发:

一、Spring Security整合到SSM项目

1. pom文件引入包

2. web.xml 配置

3. 添加 spring-security.xml 文件

二、Spring Security实战应用

1. 项目结构

2. pom文件引入

3. web.xml 配置

4. Spring 配置 applicationContext.xml

5. spring-security.xml 配置

6. springmvc.xml 配置

7. 创建实体类

8. DAO层实现数据查询

9. SystemDao 接口编写(数据层接口类)

10. SystemService接口及实现类SystemServiceImpl编写

11. SystemController 控制器编写

12. SpringSecurity实战讲解

13. 运行项目查看效果


前言

实战前提条件:
基础的SSM项目已集成完毕。在此基础上集成Spring Security实现web项目的安全保护 。

本文版本说明:
JDK:1.8
spring.version:5.2.12.RELEASE
Spring Security.version:4.2.5.RELEASE
Spring Security标签库:4.2.3.RELEASE

实战目标:
Authentication:认证,实现用户认证登录
Authorization:授权,设定用户的资源,访问权限。


实战开发:

一、Spring Security整合到SSM项目

1. pom文件引入包

        
        
            org.springframework.security
            spring-security-web
            4.2.5.RELEASE
        
        
            org.springframework.security
            spring-security-config
            4.2.5.RELEASE
        

        
        
            org.springframework.security
            spring-security-taglibs
            4.2.3.RELEASE
        

注:本项目完整的pom文件稍后附上

2. web.xml 配置

注:先说说web.xml配置文件中Spring家族的加载顺序。
先启动spring ioc容器 --> 再启动spring-security --> 然后启动springmvc


  
  
    springSecurityFilterChain
    org.springframework.web.filter.DelegatingFilterProxy
  
  
    springSecurityFilterChain
    /*
  

  
  Archetype Created Web Application
  
    org.springframework.web.context.ContextLoaderListener
  
  
  
    contextConfigLocation
    
      classpath:spring/applicationContext.xml 
      classpath:spring/spring-security.xml 
    
  

注:本项目完整的web.xml配置稍后附上

3. 添加 spring-security.xml 文件

注:本文件使用form-login的方式进行认证,在项目resources文件下新建spring文件夹(如果没有的话)




    
    
        
        
        
        

        
        
    

    
    
        
        
            
                
            
        
    


以上为spring-security.xml 的基础配置,到此Spring Security整合到SSM项目中已经完毕!运行项目后,所有资源会被拦截,跳转到默认登录页要求用户进行登录认证后才能访问项目资源。如图:

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第1张图片

二、Spring Security实战应用

1. 项目结构

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第2张图片

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第3张图片

2. pom文件引入




    4.0.0

    com.wqbr
    wqdemotwo
    1.0-SNAPSHOT
    war

    wqdemotwo Maven Webapp
    
    http://www.example.com

    
        UTF-8
        1.8
        1.8
        5.2.12.RELEASE
    

    
        
        
            org.aspectj
            aspectjweaver
            1.6.8
        
        
            org.springframework
            spring-aop
            ${spring.version}
        
        
            org.springframework
            spring-context
            ${spring.version}
        
        
            org.springframework
            spring-web
            ${spring.version}
        
        
            org.springframework
            spring-webmvc
            ${spring.version}
        
        
            org.springframework
            spring-test
            ${spring.version}
        
        
            org.springframework
            spring-tx
            ${spring.version}
        
        
            org.springframework
            spring-jdbc
            ${spring.version}
        
        
        
            org.springframework.security
            spring-security-web
            4.2.5.RELEASE
        
        
            org.springframework.security
            spring-security-config
            4.2.5.RELEASE
        
        
        
            org.springframework.security
            spring-security-taglibs
            4.2.3.RELEASE
        

        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.13.4
        

       
        
            javax.servlet.jsp
            jsp-api
            2.0
            provided
        
        
        
            jstl
            jstl
            1.2
        
        
        
            javax.servlet
            servlet-api
            2.5
            provided
        

        
        
            junit
            junit
            4.11
            test
        

        
        
            org.mybatis
            mybatis
            3.4.5
        
        
            org.mybatis.generator
            mybatis-generator-core
            1.3.5
        
        
        
            org.mybatis
            mybatis-spring
            2.0.7
        
        
        
            com.oracle.database.jdbc
            ojdbc8
            21.3.0.0
        
        
            cn.easyproject
            orai18n
            12.1.0.2.0
        

        
        
            com.alibaba
            druid
            1.1.12
        

    

    
        wqdemotwo
        
            
                org.apache.maven.plugins
                maven-source-plugin
                2.1.1
                
                    
                        attach-sources
                        
                            jar-no-fork
                        
                    
                
                
                    true
                
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.1
                
                    1.8
                    1.8
                    UTF-8
                
            
            
                org.apache.maven.plugins
                maven-war-plugin
                2.6
                
                    true
                
            
        
    

3. web.xml 配置

配置web.xml,加载spring(applicationContext.xml --spring默认配置文件),加载spring-security,加载springmvc。





  
  
    characterEncodingFilter
    org.springframework.web.filter.CharacterEncodingFilter
    
      encoding
      UTF-8
    
    
      forceEncoding
      true
    
  
  
    characterEncodingFilter
    /*
  
  

  
  
    springSecurityFilterChain
    org.springframework.web.filter.DelegatingFilterProxy
  
  
    springSecurityFilterChain
    /*
  

  
  
  
    contextConfigLocation
    
      classpath:spring/applicationContext.xml
      classpath:spring/spring-security.xml
    
  
  Archetype Created Web Application
  
    org.springframework.web.context.ContextLoaderListener
  

  
  
    dispatcherServlet
    org.springframework.web.servlet.DispatcherServlet
    
    
      
      contextConfigLocation
      
      
      
        classpath:spring/springmvc.xml
      
    
    
    1
  
  
    dispatcherServlet
    /
  

  



4. Spring 配置 applicationContext.xml

指定扫描包,数据源,整合集成接管mybatis。

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第4张图片



    
    
    
        
    

    
    
        
    

    
    
        
        
        
        
    

    

    
    
        
        
            
                
                classpath:mapping/SystemDao.xml
            
        
    

    
    
        
        
    

5. spring-security.xml 配置




    
    

        
        

        
        

        
        
        
        
        

        
        
        

        
        

        
        
        

        
        

        
        

        
        
    

    
    
        
        
            
            
        
    

    
    


    
    


6. springmvc.xml 配置




    
    
    
        
        
    

    
    
    
    

    
    
         
         
    

    
    
    
    

7. 创建实体类

注:重点在SysUser实体类。实现UserDetails接口 复写接口的方法进行实现,建立各方法的对应属性到用户表中(不一定全建对应属性)。

我们先来看下UserDetails接口类的源码:

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第5张图片

红色标注的3项建立在用户实体领域类中,如下SysUser 用户实体类代码:

package com.wqbr.domain;


import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

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

/**
 * 系统用户,封装用户数据,实现 UserDetails 接口
 * @author lv
 * @date 2024年1月11日
 */
public class SysUser implements UserDetails {

  private static final long serialVersionUID = 1L;

  private String id;
  private String username; //从UserDetails的重写方法中返回
  private String password; //从UserDetails的重写方法中返回
  private Date addtime;
  private boolean accountnonexpired; //账户是否过期,从UserDetails的重写方法中返回
  private boolean accountnonlocked; //账户是否锁定,从UserDetails的重写方法中返回
  private boolean credentialsnonexpired; //密码是否过期,从UserDetails的重写方法中返回
  private boolean enabled; //账户是否可用,从UserDetails的重写方法中返回

  // 储存用户拥有的所有权限
  private List authorities = new ArrayList<>(); //从UserDetails的重写方法中返回


  public String getId() {
    return id;
  }

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

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

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

  public Date getAddtime() {
    return addtime;
  }

  public void setAddtime(Date addtime) {
    this.addtime = addtime;
  }

  // 返回用户权限,上面声明了权限集合对象 authorities
  @Override
  public Collection getAuthorities() {
    return this.authorities;
  }

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

  // 返回用户密码,上面声明了属性 password
  @Override
  public String getPassword() {
    return password;
  }

  // 返回用户名,上面声明了属性 username
  @Override
  public String getUsername() {
    return username;
  }

  @Override
  public boolean isAccountNonExpired() {
    return accountnonexpired;
  }

  public void setAccountnonexpired(boolean accountnonexpired) {
    this.accountnonexpired = accountnonexpired;
  }

  @Override
  public boolean isAccountNonLocked() {
    return accountnonlocked;
  }

  public void setAccountnonlocked(boolean accountnonlocked) {
    this.accountnonlocked = accountnonlocked;
  }

  @Override
  public boolean isCredentialsNonExpired() {
    return credentialsnonexpired;
  }

  public void setCredentialsnonexpired(boolean credentialsnonexpired) {
    this.credentialsnonexpired = credentialsnonexpired;
  }

  @Override
  public boolean isEnabled() {
    return enabled;
  }

  public void setEnabled(boolean enabled) {
    this.enabled = enabled;
  }
}
注:private List authorities = new ArrayList<>(); 此属性稍后赋值演示
角色(SysRole )和资源(SysPermission)实体类代码参见以下文章建立: spirng框架之spring security(二)insert 语句补充-CSDN博客https://blog.csdn.net/u011529483/article/details/135467110?spm=1001.2014.3001.5501

8. DAO层实现数据查询

SystemDao.xml,mybatis的mapper文件(映射SQL语句)





    
    

    
    

9. SystemDao 接口编写(数据层接口类)

package com.wqbr.persistence;

import com.wqbr.domain.SysPermission;
import com.wqbr.domain.SysUser;

import java.util.List;

public interface SystemDao {
    /**
     * 查询当前用户对象
     */
    public SysUser findByUsername(String username);

    /**
     * 查询当前用户拥有的资源
     */
    public List findPermissionByUsername(String username);
}

10. SystemService接口及实现类SystemServiceImpl编写

package com.wqbr.service;

import com.wqbr.domain.SysPermission;

import java.util.List;

/**
 * 系统服务接口
 * @author lv
 * @date 2024年1月11日
 */
public interface SystemService {
    /**
     * 查询当前用户拥有的资源
     */
    public List findPermissionByUsername(String username);
}
package com.wqbr.service.impl;

import com.wqbr.domain.SysPermission;
import com.wqbr.persistence.SystemDao;
import com.wqbr.service.SystemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;


/**
 * 系统服务接口实现
 * @author lv
 * @date 2024年1月11日
 */
@Service
public class SystemServiceImpl implements SystemService {

    @Autowired
    private SystemDao systemDao;

    @Override
    public List findPermissionByUsername(String username) {
        return systemDao.findPermissionByUsername(username);
    }
}

11. SystemController 控制器编写

package com.wqbr.controller;

import com.wqbr.domain.Menus;
import com.wqbr.domain.SysPermission;
import com.wqbr.domain.SysUser;
import com.wqbr.service.SystemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * 系统用户控制器
 * @author lv
 * @date 2024年1月11日
 */
@Controller
@RequestMapping("/system")
public class SystemController {

    /**
     * 自动装配SystemService接口
     */
    @Autowired
    private SystemService systemService;

    /**
     * 处理超链接发送出来的请求
     * @param model
     * @return
     */
    @RequestMapping(path = "/hello")
    public String sayHello(Model model){
        System.out.println("入门方法执行了2...");
        // 配置了视图解析器后,写法
        return "main/index";
    }

    @RequestMapping(path = "/haa")
    public String haa(Model model){
        System.out.println("haa   *****bb 2 999999999999999999...");
        // 向模型中添加属性msg与值,可以在html页面中取出并渲染
        //model.addAttribute("msg","hello,SpringMVC");
        // 配置了视图解析器后,写法
        return "main/index";
    }

    @RequestMapping(path = "/index")
    public String index(){
        System.out.println("index 页面进入......");
        return "main/index";
    }

    @RequestMapping(path = "/list")
    public String list(){
        System.out.println("list方法进入......");
        return "main/list";
    }

    @RequestMapping(path = "/add")
    public String add(){
        System.out.println("add方法进入......");
        return "main/add";
    }

    @GetMapping("/findMenu")
    public ModelAndView findMenus(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
        ModelAndView model = new ModelAndView("main/menu");
        SysUser user = (SysUser) authentication.getPrincipal();
        String username=user.getUsername();
        if(username!=null){
            List listMenu = new ArrayList<>();
            List pList = systemService.findPermissionByUsername(username);
            System.out.println("=-----=大小为:"+pList.size());
            for (SysPermission permission : pList) {
                if (permission.getResource_type().equals("menu")) {
                    Menus menu = new Menus();
                    menu.setId(Long.parseLong(permission.getId()));
                    menu.setName(permission.getName());
                    menu.setParentId(Long.parseLong(permission.getParent_id()));
                    menu.setParentIds(Long.parseLong(permission.getParent_ids()));
                    menu.setUrl(permission.getUrl());
                    listMenu.add(menu);
                }
            }
            //request.setAttribute("listMenus", listMenu);
            model.addObject("listMenu",listMenu);

//            for (Menus menus : listMenu) {
//                if (menus.getParentId() == 10000) { //10000为数据库中的值
//                    System.out.println("==" + menus.getName() + "[" + menus.getUrl() + "]");
//                    for (Menus menusch : listMenu) {
//                        if (menus.getId() == menusch.getParentId()) {
//                            System.out.println("---------" + menusch.getName() + "[" + menusch.getUrl() + "]");
//                        }
//                    }
//                }
//            }
        }
        return model;
    }
}

12. SpringSecurity实战讲解

现在请查看之前配置的spring-security.xml文件。

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第6张图片

如图 spring-security.xml 文件中给出了 security:form-login 的4个属性。并禁用了 csrf 。且指定了 error-page 的路径。所以需要编写 Controller 实现 login-page 及 error-page。

  • LoginController 控制器编写
package com.wqbr.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 系统用户控制器
 * @author lv
 * @date 2024年1月16日
 */
@Controller
public class LoginController {

    @RequestMapping("/login")
    public String login(){
        System.out.println("初始 指定 进入登录页面!。。。。。。。。。。。。。。");
        return "login";
    }

    /**
     * 自定义用户访问权限不足的处理方式(需要编写controller返回权限不足的页面)
     * @return
     */
    @RequestMapping("/accessDeny")
    public String accessDeny(){
        System.out.println("自定义用户访问权限不足的处理方式(需要编写controller返回权限不足的页面)。。。。。。。。。。。。。。");
        return "accessdeny";
    }
}
  • 编写 MyAuthenticationSuccessHandler 与 MyAuthenticationFailureHandler 类实现spring-security.xml 文件中 authentication-success-handler-ref 与 authentication-failure-handler-ref 属性指定的接口。(以json格式返回成功或失败)
package com.wqbr.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Service;

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;

@Service
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    // new 一个 jackson 的 对象
    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 此方法会在登录成功后进行回调
     *
     * @param authentication:表示认证成功后的信息
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        // 自己构造json字符串,返回给前端
        Map result = new HashMap<>();
        result.put("authStr", "success");
        String json = objectMapper.writeValueAsString(result);
        // 使用response设置响应头为JSON
        httpServletResponse.setContentType("text/json;charset=utf-8");
        // 回写数据
        httpServletResponse.getWriter().write(json);
    }
}
package com.wqbr.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Service;

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;

@Service
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {

    // new 一个 jackson 的 对象
    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 此方法会在登录失败后进行回调
     *
     * @param authenticationException:表示认证失败后的信息
     */
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException authenticationException) throws IOException, ServletException {
        // 自己构造json字符串,返回给前端
        Map result = new HashMap<>();
        result.put("authStr", "fail");
        String json = objectMapper.writeValueAsString(result);
        // 使用response设置响应头为JSON
        httpServletResponse.setContentType("text/json;charset=utf-8");
        // 回写数据
        httpServletResponse.getWriter().write(json);
    }
}
  • 编写login.jsp页面,登录提交路径为 spring-security.xml 中指定的 login-processing-url="/spring_security_check" 路径。且运行项目后会根据 spring-security.xml 中的 login-page="/login" 访问 LoginController 控制器的方法跳转到 login.jsp 页。
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %>
<%@ page isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


    登录页面


用户登录

用户名:
用户密码:
  • spring-security.xml文件中的拦截规则如图:

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第7张图片

  • spring-security.xml文件中的用户详情接口实现(自定义登录授权实现类)

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第8张图片

MyUserDetailsService类实现UserDetailsService接口,重写loadUserByUsername方法,实现此方法(用户登录时调用此方法,通过用户输入的登录信息查找数据库用户表进行身份认证匹配)

package com.wqbr.service.impl;

import com.wqbr.domain.SysPermission;
import com.wqbr.domain.SysUser;
import com.wqbr.persistence.SystemDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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.stereotype.Service;

import java.util.List;

/**
 * 系统用户控制器
 * @author lv
 * @date 2024年1月16日
 */
@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private SystemDao systemDao;

    /**
     * loadUserByUsername:读取用户信息
     * 返回值类型 UserDetails 是 SpringSecurity 用来封装用户数据的接口
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("-------loadUserByUsername方法加载中。。。。username:"+username);
        /**
         * name: 用户名
         * password: 密码
         * authorities: 定义权限名称
         */
//        User user = new User("admin", "123456",
//                AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_ALL"));
//        return user;

        SysUser user=systemDao.findByUsername(username);
        System.out.println("user-====="+user);
        //判断
        if(user!=null){
            System.out.println(user.getUsername()+"---====---"+user.getPassword()+"----"+user.getAddtime());
/*            List permList=systemDao.findPermissionByUsername(user.getUsername());
            StringBuffer sb = new StringBuffer();
            for (SysPermission sysPermission : permList) {
                sb.append(sysPermission.getUrl());
                sb.append(",");
            }
            sb.delete(sb.length()-1,sb.length());*/
            List list=AuthorityUtils.createAuthorityList("ROLE_USER","admin");
            user.setAuthorities(list); //设置权限列表
            return user;
        }
        throw new UsernameNotFoundException(username+"用户名不存在!");
    }
}

到此spring-security讲解完毕,接下来补全几个测试页面

accessdeny.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


用户访问权限不足!。。。。。。。。。。。。。。。。。。。。。。。


index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %>
<%@ page isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


    welcome!


welcome! index页面

add.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


add...! 内测页面

list.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


list...! 列表 显示

list...! || 列表 显示

13. 运行项目查看效果

登录

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第9张图片

输入错误的用户名、密码

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第10张图片

输入正确的用户名、密码

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第11张图片

登录成功后尝试访问/system/add 和 /system/list 方法请求

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第12张图片

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第13张图片

如图 /system/add 成功访问,/system/list 无法访问,因为权限不足。如下图用户详情类中没有给用户指定 ROLE_ALL 权限

现在我们关闭浏览器,重新打开浏览器。不登录的情况下访问控制器的 /system/add 请求 和 /system/index 请求。

访问 http://localhost:8080/wqdemotwo_war/system/add

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第14张图片跳回到登录页面。

访问 http://localhost:8080/wqdemotwo_war/system/index

SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第15张图片成功访问。

好了关于  spring-security 就结束了。SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_第16张图片


下一篇讲讲用户认证登录进来以后如何根据角色获取菜单资源

你可能感兴趣的:(java编程,spring学习,Mybatis学习,spring,java)