栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【项目】健康项目day7总结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【项目】健康项目day7总结

第7章 系统管理-权限设置 1. 权限控制、SpringSecurity入门及进阶 【目标】

了解认证和授权的概念

【路径】

1:认证和授权的概念

  • 认证:登录(用户名和密码)
  • 授权:访问系统功能的权限

2:权限模块的数据模型

  • 用户表
  • 角色表
  • 权限表
  • 菜单表

用户,角色是多对多

权限,角色是多对多

菜单,角色是多对多

1.1. 认证和授权概念【理解】

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

问题1:在生产环境下我们如果不登录后台系统就可以完成这些功能操作吗?

答案显然是否定的,要操作这些功能必须首先登录到系统才可以。(用户登录系统–>认证)

问题2:是不是所有用户,只要登录成功就都可以操作所有功能呢?

答案是否定的,并不是所有的用户都可以操作这些功能。不同的用户可能拥有不同的权限,这就需要进行授权了。(用户登录之后,对每个用户进行授权,通过授权去访问系统中不同的功能–>授权)

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

说白了:登陆系统了,就可以访问,没登陆就不能访问。验证用户名与密码是否存在数据库中(t_user)

授权:用户认证成功后,需要为用户授权,其实就是指定当前用户可以操作哪些功能。

​ 用户登陆后,查询获取用户所拥有的权限绑定到用户, 当进行权限验证时就可以取用与登陆用户绑定的权限与访问的资源标定的权限进行匹配

商店里的 矿泉水 3块钱 资源权限标定。标定好了需要访问这个资源时的权限

登陆用户 有多少钱?老婆给予的,老婆授权。

授权是为了做权限验证的。登陆用户身上所拥有的权限集合

/checkitem/findPage.do 查询检查项 只有健康管理师才可以访问

员工A 来登陆 (查看套餐的权限) 来访 查询检查项(/checkitem/findPage.do 健康管理师) 报没有权限

认证与授权的目的,更好的保护资源(使用后台管理功能)


本章节就是要对后台系统进行权限控制,其本质就是对用户进行认证和授权。

1.2. 权限模块数据模型

前面已经分析了认证和授权的概念,要实现最终的权限控制,需要有一套表结构支撑:

用户表t_user、权限表t_permission、角色表t_role、菜单表t_menu、用户角色关系表t_user_role、角色权限关系表t_role_permission、角色菜单关系表t_role_menu。

表之间关系如下图:

通过上图可以看到,权限模块共涉及到7张表。在这7张表中,角色表起到了至关重要的作用,其处于核心位置,我们把基于角色的权限控制叫做RBAC,因为用户、权限、菜单都和角色是多对多关系。

接下来我们可以分析一下在认证和授权过程中分别会使用到哪些表:

认证过程:只需要用户表就可以了,在用户登录时可以查询用户表t_user进行校验,判断用户输入的用户名和密码是否正确。

授权过程:用户必须完成认证之后才可以进行授权,首先可以根据用户查询其角色,再根据角色查询对应的菜单,这样就确定了用户能够看到哪些菜单。然后再根据用户的角色查询对应的权限,这样就确定了用户拥有哪些权限。所以授权过程会用到上面7张表。

【小结】
  1. 认证和授权

    • 认证: 提供账号和密码进行登录认证, 系统知道你的身份
    • 授权: 根据不同的身份, 赋予不同的权限,不同的权限,可访问系统不同的功能( 系统的功能也要标定访问权限)
  2. RBAC权限模块数据模型(基于角色的权限控制)

    • 用户表
    • 角色表
    • 权限表
    • 菜单表

    用户,角色是多对多 用户角色表

    权限,角色是多对多 角色权限表

    菜单,角色是多对多 角色菜单表

    一共7张表

1.3. Spring Security简介 【目标】

知道什么是Spring Security

【路径】
  1. Spring Security简介
  2. Spring Security使用需要的坐标
【讲解】

Spring Security是 Spring提供的安全认证服务的框架。 使用Spring Security可以帮助我们来简化认证和授权的过程。官网:https://spring.io/projects/spring-security

对应的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框架。

【小结】
  1. SpringSecurity是Spring家族的一个安全框架, 简化我们开发里面的认证和授权过程, (登陆, 访问url时的权限控制 secuirty帮我们做了)
  2. SpringSecurity内部封装了Filter(只需要在web.xml容器中配置一个过滤器–代理过滤器,真实的过滤器(12个)在spring的容器中配置)
  3. 常见的安全框架
    • Spring的 SpringSecurity 配置复杂 有个好老爸(spring) 无缝整合 链式模式
    • Apache的Shiro http://shiro.apache.org/ 比较简单 apache 写整合 外观者模式
1.4. Spring Security入门案例-【重点】 【目标】

【需求】

​ 使用Spring Security进行控制: 网站(一些页面)需要登录才能访问(认证)

【路径】
  1. 创建Maven health_parent的子工程 springsecurity_demo,导入坐标(依赖health_interface)
  2. 配置web.xml(前端控制器加载spring, SpringSecurity代理过滤器)
  3. 创建spring-security.xml(核心配置文件, spring要加载这个配置)
【讲解】 1.4.1. 工程搭建

创建maven工程,打包方式为war,为了方便起见我们可以让入门案例工程依赖health_interface,这样相关的依赖都继承过来了。

pom.xml



    4.0.0

    com.itheima
    springsecurity_demo
    1.0-SNAPSHOT

    war

    
        UTF-8
        1.8
        1.8
    

    
        
            com.itheima
            health_interface
            1.0-SNAPSHOT
        
    

内置提供index.html页面,内容为“登录成功”!!

1.4.2. 配置web.xml

【路径】

1:DelegatingFilterProxy用于整合第三方框架(代理过滤器,非真正的过滤器,真正的过滤器需要在spring的配置文件)

2:springmvc的核心控制器

在web.xml中主要配置SpringMVC的DispatcherServlet和用于整合第三方框架的DelegatingFilterProxy(代理过滤器,真正的过滤器在spring的配置文件),用于整合Spring Security。




    

        springSecurityFilterChain

        org.springframework.web.filter.DelegatingFilterProxy
    
    
        springSecurityFilterChain
        
public class UserService implements UserDetailsService {

    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //提供用户的名称、密码、权限集合
        // 通过用户名来查询数据库, 查询角色及权限
        com.itheima.health.pojo.User userInDB = findByUsername(username);
        // String username,
        // String password, 数据库中的密码, 密码校验(security帮我们做了)
        // Collection authorities 权限集合
        List authorities = new ArrayList();

        // 遍历用户身上的角色
        Set roles = userInDB.getRoles();
        if(null != roles){
            for (Role role : roles) {
                // 授予的权限
                // 构造方法要的是一个角色名
                GrantedAuthority ga = new SimpleGrantedAuthority(role.getName());
                authorities.add(ga);
                for (Permission permission : role.getPermissions()) {
                    // 权限
                    ga = new SimpleGrantedAuthority(permission.getName());
                    authorities.add(ga);
                }
            }
        }

        // 登陆用户的认证信息,名称、密码、权限集合
        User user = new User(username,"{noop}" + userInDB.getPassword(),authorities);

        return user;
    }

    
    private com.itheima.health.pojo.User findByUsername (String username){
        if("admin".equals(username)) {
            com.itheima.health.pojo.User user = new com.itheima.health.pojo.User();
            user.setUsername("admin");
            user.setPassword("admin");

            Role role = new Role();
            role.setName("ROLE_ADMIN");
            Permission permission = new Permission();
            permission.setName("ADD_CHECKITEM");
            role.getPermissions().add(permission);

            Set roleList = new HashSet();
            roleList.add(role);

            user.setRoles(roleList);
            return user;
        }
        return null;
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        // 加密密码
        //System.out.println(encoder.encode("1234"));

        // 验证密码
        // 原密码
        // 加密后的密码
        System.out.println(encoder.matches("1234", "$2a$10$P7Qx8eKUPX5lngz9UEstUOaDRldEWrj9Rbyox/ShyeoxvPbEHTvni"));
        System.out.println(encoder.matches("1234", "$2a$10$5q.0a0F0hRix8TBJxQ4DB.ekwGzPs3e47hoQVNR7cihi/Rob.G3T6"));
        System.out.println(encoder.matches("1234", "$2a$10$voh.1PJRXQazoijK72sIoOslpmLYPyB.6LtT7aUrXqUO5G8Aw43we"));

        System.out.println(encoder.matches("1234", "$2a$10$u/BcsUUqZNWUxdmDhbnoeeobJy6IBsL1Gn/S0dMxI2RbSgnMKJ.4a"));
    }
}

第二步:spring-security.xml:

本章节我们提供了UserService实现类,并且按照框架的要求实现了UserDetailsService接口。在spring配置文件中注册UserService,指定其作为认证过程中根据用户名查询用户信息的处理类。当我们进行登录操作时,spring security框架会调用UserService的loadUserByUsername方法查询用户信息,并根据此方法中提供的密码和用户页面输入的密码进行比对来实现认证操作。

1.5.4. 对密码进行加密

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

常见的密码加密方式有:

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

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

MD5可进行加盐加密,保证安全

public class TestMD5 {

    @Test
    public void testMD5(){
        // 密码同样是1234却变成了密码不相同
        System.out.println(MD5Utils.md5("1234xiaowang")); //a8231077b3d5b40ffadee7f4c8f66cb7
        System.out.println(MD5Utils.md5("1234xiaoli")); //7d5250d8620fcdb53b25f96a1c7be591
    }
}

同样的密码值,盐值不同,加密的结果不同。

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

spring security中的BCryptPasswordEncoder方法采用SHA-256 +随机盐+密钥对密码进行加密。SHA系列是Hash算法,不是加密算法,使用加密算法意味着可以解密(这个与编码/解码一样),但是采用Hash处理,其过程是不可逆的。

(1)加密(encode):注册用户时,使用SHA-256+随机盐+密钥把用户输入的密码进行hash处理,得到密码的hash值,然后将其存入数据库中。

(2)密码匹配(matches):用户登录时,密码匹配阶段并没有进行密码解密(因为密码经过Hash处理,是不可逆的),而是使用相同的算法把用户输入的密码进行hash处理,得到密码的hash值,然后将其与从数据库中查询到的密码hash值进行比较。如果两者相同,说明用户输入的密码正确。

这正是为什么处理密码时要用hash算法,而不用加密算法。因为这样处理即使数据库泄漏,黑客也很难破解密码。

建立测试代码

package com.itheima.security.test;

import org.junit.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class TestSpringSecurity {
    // SpringSecurity加盐加密
    @Test
    public void testSpringSecurity(){
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        // 加密密码
        //System.out.println(encoder.encode("1234"));

        // 验证密码
        // 原密码
        // 加密后的密码
        System.out.println(encoder.matches("1234", "$2a$10$P7Qx8eKUPX5lngz9UEstUOaDRldEWrj9Rbyox/ShyeoxvPbEHTvni"));
        System.out.println(encoder.matches("1234", "$2a$10$5q.0a0F0hRix8TBJxQ4DB.ekwGzPs3e47hoQVNR7cihi/Rob.G3T6"));
        System.out.println(encoder.matches("1234", "$2a$10$voh.1PJRXQazoijK72sIoOslpmLYPyB.6LtT7aUrXqUO5G8Aw43we"));

        System.out.println(encoder.matches("1234", "$2a$10$u/BcsUUqZNWUxdmDhbnoeeobJy6IBsL1Gn/S0dMxI2RbSgnMKJ.4a"));
    }
}

加密后的格式一般为:

$2a$10$/bTVvqqlH9UiE0ZJZ7N2Me3RIgUCdgMheyTgV0B4cMCSokPa.6oCa

加密后字符串的长度为固定的60位。其中:

$是分割符,无意义;

2a是bcrypt加密版本号;

10是cost的值;

而后的前22位是salt值;

再然后的字符串就是密码的密文了。

实现步骤:

【路径】

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

2:修改UserService实现类

【讲解】

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


    
    
        
        
    




第二步:修改UserService实现类

package com.itheima.security;

import com.google.gson.internal.$Gson$Preconditions;
import com.itheima.health.pojo.Permission;
import com.itheima.health.pojo.Role;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class UserService implements UserDetailsService {

    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //提供用户的名称、密码、权限集合
        // 通过用户名来查询数据库, 查询角色及权限
        com.itheima.health.pojo.User userInDB = findByUsername(username);
        // String username,
        // String password, 数据库中的密码, 密码校验(security帮我们做了)
        // Collection authorities 权限集合
        List authorities = new ArrayList();

        // 遍历用户身上的角色
        

        //测试其它方式的认证
        GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_ADMIN");
        authorities.add(ga);
        ga = new SimpleGrantedAuthority("add");
        authorities.add(ga);

        // 登陆用户的认证信息,名称、密码、权限集合
        //User user = new User(username,"{noop}" + userInDB.getPassword(),authorities);
        // 使用加密的密码后,去除{noop}
        User user = new User(username,userInDB.getPassword(),authorities);

        return user;
    }

    
    private com.itheima.health.pojo.User findByUsername (String username){
        if("admin".equals(username)) {
            com.itheima.health.pojo.User user = new com.itheima.health.pojo.User();
            user.setUsername("admin");
            //user.setPassword("admin");
            // 使用密码加密器encoder, 加密后的密码
            user.setPassword("$2a$10$P7Qx8eKUPX5lngz9UEstUOaDRldEWrj9Rbyox/ShyeoxvPbEHTvni");

            Role role = new Role();
            role.setName("ROLE_ADMIN");
            Permission permission = new Permission();
            permission.setName("ADD_CHECKITEM");
            role.getPermissions().add(permission);

            Set roleList = new HashSet();
            roleList.add(role);

            user.setRoles(roleList);
            return user;
        }
        return null;
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        // 加密密码
        //System.out.println(encoder.encode("1234"));

        // 验证密码
        // 原密码
        // 加密后的密码
        System.out.println(encoder.matches("1234", "$2a$10$P7Qx8eKUPX5lngz9UEstUOaDRldEWrj9Rbyox/ShyeoxvPbEHTvni"));
        System.out.println(encoder.matches("1234", "$2a$10$5q.0a0F0hRix8TBJxQ4DB.ekwGzPs3e47hoQVNR7cihi/Rob.G3T6"));
        System.out.println(encoder.matches("1234", "$2a$10$voh.1PJRXQazoijK72sIoOslpmLYPyB.6LtT7aUrXqUO5G8Aw43we"));

        System.out.println(encoder.matches("1234", "$2a$10$u/BcsUUqZNWUxdmDhbnoeeobJy6IBsL1Gn/S0dMxI2RbSgnMKJ.4a"));
    }
}

使用密码加密器小结:

  1. security.xml添加bean 加密器

    
    
  2. security.xml使用加密器

    
            
                
        
    
    
  3. 修改UserService中admin用户的密码为密文, 去{noop}

1.5.5. 配置多种验证规则(对页面)

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

修改spring-security.xml文件:

前提:,开启对表达式的支持












测试:

登录后可以访问a.html,b.html,c.html,不能访问d.html(抛出403的异常)

1.5.6. 注解方式权限控制(对类)

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

【路径】

1:在spring-security.xml文件中配置组件扫描和mvc的注解驱动,用于扫描Controller

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

3:创建Controller类并在Controller的方法上加入注解(@PreAuthorize)进行权限控制

实现步骤:

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



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


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

package com.itheima.controller;

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

@Controller
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping("/add")
    @PreAuthorize("hasAuthority('add')")//表示用户必须拥有add权限才能调用当前方法
    public String add(){
        System.out.println("add...");
        return null;
    }

    @RequestMapping("/update")
    @PreAuthorize("hasRole('ROLE_ADMIN')")//表示用户必须拥有ROLE_ADMIN角色才能调用当前方法
    public String update(){
        System.out.println("update...");
        return null;
    }

    @RequestMapping("/delete")
    @PreAuthorize("hasRole('ABC')")//表示用户必须拥有ABC角色才能调用当前方法
    public String delete(){
        System.out.println("delete...");
        return null;
    }
}

测试delete方法不能访问

小结:

  1. 开启注解支持

    
    
  2. 使用mvc:annotation-driven

  3. 创建controller,且加入扫包context:component-scan

  4. controller方法@PreAuthorize(hasAuthority/hasRole)

  5. 注解掉

    
        @Reference
        private UserService userService;
    
        
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
           //根据登陆用户名称查询用户权限信息
           //t_user -> t_user_role -> t_role -> t_role_permission -> t_permission
           //找出用户所拥有的角色,及角色下所拥有的权限集合
           //User.roles(角色集合).permissions(权限集合)
            User user = userService.findByUsername(username);
            if(null != user){
    
                // 用户名
                // 密码
                String password = user.getPassword();
                // 权限集合
                List authorities = new ArrayList();
                // 授权
    
                // 用户所拥有的角色
                SimpleGrantedAuthority sai = null;
                Set roles = user.getRoles();
                if(null != roles){
                    for (Role role : roles) {
                        // 角色用关键字, 授予角色
                        sai = new SimpleGrantedAuthority(role.getKeyword());
                        authorities.add(sai);
                        // 权限, 角色下的所有权限
                        Set permissions = role.getPermissions();
                        if(null != permissions){
                            for (Permission permission : permissions) {
                                // 授予权限
                                sai = new SimpleGrantedAuthority(permission.getKeyword());
                                authorities.add(sai);
                            }
                        }
                    }
                }
    
                return new org.springframework.security.core.userdetails.User(username,password,authorities);
            }
            // 返回null, 限制访问
            return null;
        }
    }
    
    

    使用debug跟踪调试,查看user。

    2.2.3. 第三步:Service、Dao接口、Mapper映射文件

    创建UserService服务接口、服务实现类、Dao接口、Mapper映射文件等

    【路径】

    1:UserService.java接口

    2:UserServiceImpl.java类

    3:UserDao.java(使用用户名称查询用户)

    4:RoleDao.java(使用用户id查询角色集合)

    5:PermissionDao.java(使用角色id查询权限集合)

    6:UserDao.xml(使用用户名称查询用户)

    7:RoleDao.xml(使用用户id查询角色集合)

    8:PermissionDao.xml(使用角色id查询权限集合)

    【讲解】

    1:服务接口

    package com.itheima.health.service;
    
    import com.itheima.health.pojo.User;
    
    
    public interface UserService {
        
        User findByUsername(String username);
    }
    
    

    2:服务实现类

    package com.itheima.health.service.impl;
    
    import com.alibaba.dubbo.config.annotation.Service;
    import com.itheima.health.dao.UserDao;
    import com.itheima.health.pojo.User;
    import com.itheima.health.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    
    
    @Service(interfaceClass = UserService.class)
    public class UserServiceImpl implements UserService {
    
        @Autowired
        private UserDao userDao;
    
        
        @Override
        public User findByUsername(String username) {
            return userDao.findByUsername(username);
        }
    }
    
    

    3:Dao接口

    (1)UserDao

    package com.itheima.health.dao;
    
    import com.itheima.health.pojo.User;
    
    
    public interface UserDao {
        
        User findByUsername(String username);
    }
    
    

    4:Mapper映射文件

    (1)UserDao.xml

    
    
    
    
        
    
        
            
            
            
            
                
                
                
                
                    
                    
                    
                
            
        
    
    
    2.2.4. 第四步:springmvc.xml

    修改health_web工程中的springmvc.xml文件,修改dubbo批量扫描的包路径

    之前的包扫描

    
    

    现在的包扫描

    
    

    **注意:**此处原来扫描的包为com.itheima.controller,现在改为com.itheima包的目的是需要将我们上面定义的SpringSecurityUserService也扫描到,因为在SpringSecurityUserService的loadUserByUsername方法中需要通过dubbo远程调用名称为UserService的服务。

    2.2.5. 第五步:spring-security.xml

    【路径】

    1:定义哪些链接可以放行

    2:定义哪些链接不可以放行,即需要有角色、权限才可以放行

    3:认证管理,定义登录账号名和密码,并授予访问的角色、权限

    4:设置在页面可以通过iframe访问受保护的页面,默认为不允许访问,需要添加security:frame-options policy=“SAMEORIGIN”

    【讲解】

    在health_web工程中提供spring-security.xml配置文件

    
    
    
         list = checkItemService.findAll();
            // 封装返回的结果
            return new Result(true, MessageConstant.QUERY_CHECKITEM_SUCCESS,list);
        }
    
        
        @PostMapping("/add")
        @PreAuthorize("hasAuthority('CHECKITEM_ADD')")
        public Result add(@RequestBody CheckItem checkitem){
            // 调用业务服务
            checkItemService.add(checkitem);
            // 响应结果给前端
            return new Result(true, MessageConstant.ADD_CHECKITEM_SUCCESS);
        }
    
        
        @PostMapping("/findPage")
        @PreAuthorize("hasAuthority('CHECKITEM_QUERY')")
        public Result findPage(@RequestBody QueryPageBean queryPageBean){
            // 调用业务来分页
            PageResult pageResult = checkItemService.findPage(queryPageBean);
    
            //return pageResult;
            // 返回给页面, 包装到Result, 统一风格
            return new Result(true, MessageConstant.QUERY_CHECKITEM_SUCCESS,pageResult);
        }
    
        
        @PostMapping("/deleteById")
        public Result deleteById(int id){
            // 调用业务服务
            //try {
                checkItemService.deleteById(id);
            //} catch (Exception e) {
             //   e.printStackTrace();
            //}
            // 响应结果
            return new Result(true, MessageConstant.DELETE_CHECKITEM_SUCCESS);
        }
    
        
        @GetMapping("/findById")
        public Result findById(int id){
            CheckItem checkItem = checkItemService.findById(id);
            return new Result(true, MessageConstant.QUERY_CHECKITEM_SUCCESS,checkItem);
        }
    
        
        @PostMapping("/update")
        public Result update(@RequestBody CheckItem checkitem){
            // 调用业务服务
            checkItemService.update(checkitem);
            // 响应结果给前端
            return new Result(true, MessageConstant.EDIT_CHECKITEM_SUCCESS);
        }
    }
    
    
    2.2.8. 第八步:异常捕获

    修改health_web项目中的HealthExceptionAdvice

    package com.itheima.health.controller;
    
    import com.itheima.health.entity.Result;
    import com.itheima.health.exception.HealthException;
    import org.springframework.security.access.AccessDeniedException;
    import org.springframework.security.authentication.BadCredentialsException;
    import org.springframework.security.authentication.InternalAuthenticationServiceException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    
    // 与前端约定好的,返回的都是json数据
    @RestControllerAdvice
    public class HealExceptionAdvice {
    
        
        @ExceptionHandler(HealthException.class)
        public Result handleHealthException(HealthException he){
            return new Result(false, he.getMessage());
        }
    
        
        @ExceptionHandler(Exception.class)
        public Result handleException(Exception he){
            he.printStackTrace();
            return new Result(false, "发生未知错误,操作失败,请联系管理员");
        }
    
        
        @ExceptionHandler(BadCredentialsException.class)
        public Result handBadCredentialsException(BadCredentialsException he){
            return handleUserPassword();
        }
    
        
        @ExceptionHandler(InternalAuthenticationServiceException.class)
        public Result handInternalAuthenticationServiceException(InternalAuthenticationServiceException he){
            return handleUserPassword();
        }
    
        private Result handleUserPassword(){
            return new Result(false, "用户名或密码错误");
        }
    
        
        @ExceptionHandler(AccessDeniedException.class)
        public Result handAccessDeniedException(AccessDeniedException he){
            return new Result(false, "没有权限");
        }
    }
    
    
    2.3. 显示用户名

    【路径】

    1:引入js

    2:定义loginUsername属性

    3:使用钩子函数,调用ajax,查询登录用户(从SpringSecurity中获取),赋值username属性

    4:修改页面,使用{{loginUsername}}显示用户信息

    【讲解】

    前面我们已经完成了认证和授权操作,如果用户认证成功后需要在页面展示当前用户的用户名。Spring Security在认证成功后会将用户信息保存到框架提供的上下文对象中,所以此处我们就可以调用Spring Security框架提供的API获取当前用户的username并展示到页面上。

    实现步骤:

    第一步:在main.html页面中修改,定义username模型数据基于VUE的数据绑定展示用户名,发送ajax请求获取username

    (1):引入js

    
    

    (2):定义loginUsername属性

    (3):使用钩子函数mounted,调用ajax

    (4)显示用户名

    页面最终如下

    
    
    
        
        
        
        传智健康
        
        
        
        
        
        
        
        
    
    
        

    第二步:创建UserController并提供getUsername方法

    package com.itheima.health.controller;
    
    import com.itheima.health.constant.MessageConstant;
    import com.itheima.health.entity.Result;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    
    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        
        @GetMapping("/getUsername")
        public Result getUsername(){
            // 获取登陆用户的认证信息
            User loginUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            // 登陆用户名
            String username = loginUser.getUsername();
            // 返回给前端
            return new Result(true, MessageConstant.GET_USERNAME_SUCCESS,username);
        }
    }
    
    

    通过debug调试可以看到Spring Security框架在其上下文中保存的用户相关信息:

    显示当前登录人:

    2.4. 用户退出

    【路径】

    1:在main.html中提供的退出菜单上加入超链接

    2:在spring-security.xml文件中配置

    【讲解】

    第一步:在main.html中提供的退出菜单上加入超链接

    
            退出
    
    

    第二步:在spring-security.xml文件中配置

    
    
    【小结】

    1:导入SpringSecurity环境

    (1)pom.xml中添加依赖

    (2)web.xml添加代理过滤器

    2:实现认证和授权

    (1)导入login.html登录页面 webapp目录下

    (2)认证:SpringSecurityUserService(@Component),实现UserDetailsService接口

    (3)创建UserService类、UserDao接口类、UserDao映射文件(使用用户名查询当前用户信息,包括角色集合和权限集合)

    (4)springmvc.xml(dubbo注解扫描范围扩大, 扫到SpringSecurityUserService)

    (5)spring-security.xml(重点 存小抄 )

    • 静态资源过滤
    • 拦截的规则 security:http auto-config…, intercept-url, form-login, form-logout, csrf, security:header
    • 开启注解支持
    • 关闭跨域访问限制
    • 认证管理器->提供者user-service-ref->加密器
    • 加密器

    (6)springmvc.xml(导入spring-security.xml)

    (7)CheckItemController类(@PreAuthorize(“hasAuthority(‘CHECKITEM_ADD’)”):对类中的方法完成权限控制), hasAuthority 权限校验(t_permission.keyword), hasRole角色校验(t_role.keyword)

    (8)checkitem.html(如果没有权限,可以提示错误信息)

    异常捕获HealthExceptionHandler, AccessDeniedException, return 没有权限的result

    3:显示用户名

    从SecurityContextHolder对象中获取认证的用户信息,页面定义一个vue的data变量业接收,使用插值表达式在页面显示,页面加载时发送请求(vue created axios)

    // 获取登陆用户的认证信息
    User loginUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    

    在jsp中获取登陆用户信息

    ${sessionScope.SPRING_SECURITY_CONTEXT.authentication.principal.username}
    

    4:用户退出

    调用/logout.do security帮我们做好了

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/287713.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号