springSecurity-入门到实战(整合SSM-整合Springboot待更新)

SpringSecurty

认证和授权概念

前面我们已经完成了传智健康后台管理系统的部分功能,例如检查项管理、检查组管理、套餐管理、预 约设置等。接下来我们需要思考2个问题:

问题1:在生产环境下我们如果不登录后台系统就可以完成这些功能操作吗? 答案显然是否定的,要操作这些功能必须首先登录到系统才可以。

问题2:是不是所有用户,只要登录成功就都可以操作所有功能呢? 答案是否定的,并不是所有的用户都可以操作这些功能。

不同的用户可能拥有不同的权限,这就需要进 行授权了。

 

认证:系统提供的用于识别用户身份的功能,通常提供用户名和密码进行登录其实就是在进行认证,认 证的目的是让系统知道你是谁。

授权:用户认证成功后,需要为用户授权,其实就是指定当前用户可以操作哪些功能。 本章节就是要对后台系统进行权限控制,其本质就是对用户进行认证和授权。

 

Spring Security简介

Spring Security是 Spring提供的安全认证服务的框架。 使用Spring Security可以帮助我们来简化认证 和授权的过程。

官网:https://spring.io/projects/spring-security

springSecurity-入门到实战(整合SSM-整合Springboot待更新)_第1张图片

对应的maven坐标:


    org.springframework.security
    spring-security-web
    5.0.5.RELEASE


    org.springframework.security
    spring-security-config
    5.0.5.RELEASE

常用的权限框架除了Spring Security,还有Apache的shiro框架。

 

SpringSecurty初体验

1、导入对应坐标

自己添加一下版本

 
        
            com.github.pagehelper
            pagehelper
        
        
        
            org.mybatis
            mybatis
        
        
            org.mybatis
            mybatis-spring
        
        
            com.github.miemiedev
            mybatis-paginator
        
        
        
            mysql
            mysql-connector-java
        
        
        
            com.alibaba
            druid
        
        
            commons-fileupload
            commons-fileupload
        
        
        
            org.springframework
            spring-context
        
        
            org.springframework
            spring-beans
        
        
            org.springframework
            spring-web
        
        
            org.springframework
            spring-webmvc
        
        
            org.springframework
            spring-jdbc
        
        
            org.springframework
            spring-aspects
        
        
            org.springframework
            spring-jms
        
        
            org.springframework
            spring-context-support
        
        
            org.springframework
            spring-test
        
        
        
            com.alibaba
            dubbo
        
        
            org.apache.zookeeper
            zookeeper
        
        
            com.github.sgroschupf
            zkclient
        
        
            junit
            junit
        
        
            com.alibaba
            fastjson
        
        
            javassist
            javassist
        
        
            commons-codec
            commons-codec
        
        
            org.apache.poi
            poi
        
        
            redis.clients
            jedis
        
        
            com.qiniu
            qiniu-java-sdk
        
        
            com.sun.jersey
            jersey-client
        
        
            org.apache.poi
            poi-ooxml
        
        
            org.springframework.security
            spring-security-web
        
        
            org.springframework.security
            spring-security-config
        
        
            org.springframework.security
            spring-security-taglibs
        
        
            com.aliyun
            aliyun-java-sdk-core
            3.3.1
        
        
            com.aliyun
            aliyun-java-sdk-dysmsapi
            1.0.0
        
        
            org.freemarker
            freemarker
            2.3.23
        
 

    
      
        org.apache.tomcat.maven
        tomcat7-maven-plugin
        
          
          85
          
          /
        
      
    
  

2、web.xml配置




    Archetype Created Web Application
    
    
        springSecurityFilterChain
        org.springframework.web.filter.DelegatingFilterProxy
    
    
        springSecurityFilterChain
        /*
    

  
    springmvc
    org.springframework.web.servlet.DispatcherServlet
    
    
      contextConfigLocation
      classpath:spring-security.xml
    
    1
  
  
    springmvc
    *.do
  

3、配置spring-security.xml



    
    
        
        
        

    

    
    
        
        
            
            
                
            
        
    

4、测试

准备一个index.html 页面




  
  Title


 hello ! welcome securty!!!

启动tomcat --》

springSecurity-入门到实战(整合SSM-整合Springboot待更新)_第2张图片

登录后访问index.html页面即可!!! 此登录页面是security自带的!!!

 

更加详细的入门案例可参考:

https://blog.csdn.net/qq_45441466/article/details/109371359 
 

SpringSecurty改进版本

前面我们已经完成了Spring Security的入门案例,通过入门案例我们可以看到,Spring Security将我们 项目中的所有资源都保护了起来,要访问这些资源必须要完成认证而且需要具有ROLE_ADMIN角色。

但是入门案例中的使用方法离我们真实生产环境还差很远,还存在如下一些问题:

1、项目中我们将所有的资源(所有请求URL)都保护起来,实际环境下往往有一些资源不需要认证也 可以访问,也就是可以匿名访问。

2、登录页面是由框架生成的,而我们的项目往往会使用自己的登录页面。

3、在配置文件中配置的密码使用明文,这非常不安全,而真实生产环境下密码需要进行加密。

本章节需要对这些问题进行改进。

 

配置可匿名访问的资源



第一步:在项目中创建pages目录,在pages目录中创建a.html和b.html

第二步:在spring-security.xml文件中配置,指定哪些资源可以匿名访问

    
    
    

即是当前pages目录下的a.html 和 b.html 页面进行权限校验

 

也可以配置pages/** 放在pages目录下所有资源不校验权限

    

通过上面的配置可以发现,pages目录下的文件可以在没有认证的情况下任意访问。

 

使用指定的登录页面

第一步:提供login.html作为项目的登录页面




  
  Title


username:
password:

第二步:修改spring-security.xml文件,指定login.html页面可以匿名访问

    

第三步:修改spring-security.xml文件,加入表单登录信息的配置

配置在 标签中:


        
        

第四步:修改spring-security.xml文件,关闭CsrfFilter过滤器

csrf: spring security 用于防止跨域攻击的!!

        
        

 

从数据库查询用户信息

如果我们要从数据库动态查询用户信息,就必须按照spring security框架的要求提供一个实现 UserDetailsService接口的实现类,并按照框架的要求进行配置即可。框架会自动调用实现类中的方法 并自动进行密码校验。

实现类代码:

package com.itheima.service;

import com.itheima.pojo.User;
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.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author panghl
 * @Date 2021/5/3 14:34
 * @Description TODO
 **/
public class SpringSecurityUserService implements UserDetailsService {

    public static Map userMap = new HashMap<>();

    static {
        User user1 = new User();
        user1.setUsername("xiaoming");
        user1.setPassword("12345");

        User user2 = new User();
        user2.setUsername("admin");
        user2.setPassword("admin");

        userMap.put(user1.getUsername(), user1);
        userMap.put(user2.getUsername(), user2);
    }

    /**
     * 根据用户名查询用户信息
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("用户输入的用户名为:" + username);
        // 根据用户名查询数据库获得用户信息(包含数据库中存储的密码信息)  --static代码块模拟了数据
        User user = userMap.get(username);
        if (user == null) {
            //用户名不存在
            return null;
        } else {
            // 将用户信息返回给框架
            // 框架会进行密码比对(页面提交的密码和数据库中查询的密码进行比对)
            List list = new ArrayList<>();
            //为当前登录用户授权,后期需要改为从数据库查询当前用户对应的权限
            list.add(new SimpleGrantedAuthority("permission_a"));//授予权限
            list.add(new SimpleGrantedAuthority("permission_b"));
            if (username.equals("admin")) {
                //用户名为admin 才授予ADMIN角色权限--即可登录
                list.add(new SimpleGrantedAuthority("ROLE_ADMIN"));//授予角色
            }
            org.springframework.security.core.userdetails.User securityUser =
                    new org.springframework.security.core.userdetails.User(username, "{noop}" + userMap.get(username).getPassword(),
                            true, true, true, true, list);

            return securityUser;
        }
    }

}

 

重启tomcat测试可知:admin拥有ADMIN角色可以登录,而xiaoming则没有ADMIN角色不能登录!

 

详细查数据库玩法可看:https://blog.csdn.net/qq_45441466/article/details/109372046

 

对密码进行加密

前面我们使用的密码都是明文的,这是非常不安全的。一般情况下用户的密码需要进行加密后再保存到 数据库中。

常见的密码加密方式有:

3DES、AES、DES:使用对称加密算法,可以通过解密来还原出原始密码

MD5、SHA1:使用单向HASH算法,无法通过计算还原出原始密码,但是可以建立彩虹表进行查表破 解

bcrypt:将salt随机并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理 salt问题

 

加密后的格式一般为:

$2a$10$/bTVvqqlH9UiE0ZJZ7N2Me3RIgUCdgMheyTgV0B4cMCSokPa.6oCa

加密后字符串的长度为固定的60位。其中:$是分隔符,无意义;2a是bcrypt加密版本号;10是cost的值;而后的前22位是salt值;再然后的字符串就是密码的密文了。

 

实现步骤:

第一步:在spring-security.xml文件中指定密码加密对象



    
    
    
    

    

    
    
        
        
        

        
        
        
        
        

    

    
    
        
        
            
            
            

        
    
    

    
    

    
    

    
    

第二步:修改UserService实现类

package com.itheima.service;

import com.itheima.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 org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author panghl
 * @Date 2021/5/3 14:34
 * @Description TODO
 **/
public class SpringSecurityUserService2 implements UserDetailsService {

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    public Map userMap = new HashMap<>();

    public void initUserData() {
        User user1 = new User();
        user1.setUsername("xiaoming");
        user1.setPassword(passwordEncoder.encode("12345"));

        User user2 = new User();
        user2.setUsername("admin");
        user2.setPassword(passwordEncoder.encode("admin"));//使用bcrypt提供的方法对密码加密

        userMap.put(user1.getUsername(), user1);
        userMap.put(user2.getUsername(), user2);
    }



    /**
     * 根据用户名查询用户信息
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("用户输入的用户名为-->2-->:" + username);
        this.initUserData();
        // 根据用户名查询数据库获得用户信息(包含数据库中存储的密码信息)  --static代码块模拟了数据
        User user = userMap.get(username);
        if (user == null) {
            //用户名不存在
            return null;
        } else {
            // 将用户信息返回给框架
            // 框架会进行密码比对(页面提交的密码和数据库中查询的密码进行比对)
            List list = new ArrayList<>();
            //为当前登录用户授权,后期需要改为从数据库查询当前用户对应的权限
            list.add(new SimpleGrantedAuthority("permission_a"));//授予权限
            list.add(new SimpleGrantedAuthority("permission_b"));
            if (username.equals("admin")) {
                //用户名为admin 才授予ADMIN角色权限--即可登录
                list.add(new SimpleGrantedAuthority("ROLE_ADMIN"));//授予角色
            }
            org.springframework.security.core.userdetails.User securityUser =
                    new org.springframework.security.core.userdetails.User(username,user.getPassword(),
                            true, true, true, true, list);

            return securityUser;
        }
    }

}

通过debug可以发现密码以及通过bcrypt方式加密了!

springSecurity-入门到实战(整合SSM-整合Springboot待更新)_第3张图片

 

补充:

对称算法:把原文A计算为密文B。同时,使用算法的逆运算,还可以把密文B还原为原文A。一般用于信息传输加密。

非对称算法: 一般是一些摘要算法,算法不可逆。即使知道算法的全部内容,也无法还原原文。

原文A计算为密文B,密文B不包含原文的所有信息,仅仅是使用原文计算出来的一个单独字符串,无法还原

 

配置多种校验规则

为了测试方便,首先在项目中创建a.html、b.html、c.html、d.html几个页面

修改spring-security.xml文件

        
        
        

        
        

        
        

        
        

修改实现类代码:

                list.add(new SimpleGrantedAuthority("add"));//授予权限

 测试可知:

xiaoming通过认证就可以访问index.jsp 和 pages目录下的a.html 

而admin用户通过认证可以访问pages目录下的所有html页面。

 

注解方式控制权限

SpringSecurity除了可以在配置文件中配置权限校验规则,还可以使用注解方式控制类中方法的调用。例如:Controller中的某个方法要求必须具有某个权限才能可以访问,此时就可以使用Spring Security框架提供的注解方式进行控制

实现步骤:

第一步:在spring-security.xml文件中配置组件扫描,用于扫描Controller

    
    

第二步:在spring-security.xml文件中开启权限注解支持

    
    

第三步:创建Controller类并在Controller的方法上加入注解进行权限控制

package com.itheima.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author panghl
 * @Date 2021/5/3 16:13
 * @Description TODO
 **/
@RestController
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping("/add")
    @PreAuthorize("hasAuthority('add')") //调用此方法要求当前用户具有add权限
    public String add(){
        System.out.println("add....");
        return "success-add";
    }

    @RequestMapping("/delete")
    @PreAuthorize("hasRole('ROLE_ADMIN')") //调用此方法要求当前用户具有ROLE_ADMIN角色
    public String delete(){
        System.out.println("delete....");
        return "success-delete";
    }


}

 

通过测试可知:

xiaoming是无法访问add / delete方法的,admin是可以操作这两个方法的!!!

 

spring-security实现方法级别、@Secured注解、JSR-250注解、页面端的权限控制:https://blog.csdn.net/qq_45441466/article/details/109558624

 

退出登录

用户完成登录后SpringSecurity框架会记录当前用户认证状态为已认证状态,即表示用户登录成功了。那用户如何退出登录呢?我们可以在spring-security.xml文件中进行如下配置:

 
        

通过上面的配置可以发现,如果用户要退出登录,只需要请求/logout.do这个URL地址就可以,同时会将当前session失效,最后页面会跳转到login页面。

 

 

 

想要获取黑马、尚硅谷等资源课程、资料、项目实战等等更多资源。可加群:1164437770(期待您的加入一起讨论)
 

 

 

 

你可能感兴趣的:(SSM,spring,java)