spring security权限控制,ECharts图形报表

第10章 权限控制、图形报表

1. 在项目中应用Spring Security

前面我们已经学习了Spring Security框架的使用方法,本章节我们就需要将Spring Security框架应用到
后台系统中进行权限控制,其本质就是认证和授权。
要进行认证和授权需要前面课程中提到的权限模型涉及的7张表支撑,因为用户信息、权限信息、菜单
信息、角色信息、关联信息等都保存在这7张表中,也就是这些表中的数据是我们进行认证和授权的依
据。所以在真正进行认证和授权之前需要对这些数据进行管理,即我们需要开发如下一些功能:
1、权限数据管理(增删改查)
2、菜单数据管理(增删改查)
3、角色数据管理(增删改查、角色关联权限、角色关联菜单)
4、用户数据管理(增删改查、用户关联角色)
鉴于时间关系,我们不再实现这些数据管理的代码开发。我们可以直接将数据导入到数据库中即可。

1.1 导入和配置

第一步:在health_parent父工程的pom.xml中导入Spring Security的maven坐标

         <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
            <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>${spring.security.version}</version>
            </dependency>

第二步:在health_backend工程的web.xml文件中配置用于整合Spring Security框架的过滤器
DelegatingFilterProxy

<?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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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/mvc
                         http://www.springframework.org/schema/mvc/spring-mvc.xsd
        				http://code.alibabatech.com/schema/dubbo
                         http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        				http://www.springframework.org/schema/context
                         http://www.springframework.org/schema/context/spring-context.xsd
                         http://www.springframework.org/schema/security
                         http://www.springframework.org/schema/security/spring-security.xsd">

    <security:http security="none" pattern="/login.html"></security:http>
    <security:http security="none" pattern="/css/**"></security:http>
    <security:http security="none" pattern="/img/**"></security:http>
    <security:http security="none" pattern="/js/**"></security:http>
    <security:http security="none" pattern="/plugins/**"></security:http>
    <!--
    auto-config:自动配置,如果设置为true,表示自动应用一些默认配置,比如框架会提供一个默认的登录页面

    user-expressions:是否使用spring security提供的表达式来描述权限
-->
    <security:http auto-config="true" use-expressions="true">
        <security:access-denied-handler ref="myExceptionAdvice"/>
        <security:headers>
            <!--            设置在页面可以通过iframe访问受保护的页面,默认为不允许访问,页面嵌套的要告诉具体策略-->
            <security:frame-options policy="SAMEORIGIN"></security:frame-options>
        </security:headers>

        <!--        配置拦截规则,/**表示拦截所有请求-->


        <!--只要认证通过就可以访问-->
        <security:intercept-url pattern="/pages/**"  access="isAuthenticated()" />

        <!--
                pattern:描述拦截规则
                asscess:指定所需的访问角色或者访问权限
        -->


        <!--      如果我们要使用自己指定的页面作为登录页面,必须配置登录表单-->
        <!--        form-login指定登录页面访问URL-->
        <security:form-login
                login-page="/login.html"
                username-parameter="username"
                password-parameter="password"
                login-processing-url="/login.do"
                default-target-url="/index.html"
                authentication-failure-url="/login.html"></security:form-login>


        <!--        csrf:对应CsrfFilter过滤器
                    disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用(403)
        -->
        <security:csrf disabled="true"></security:csrf>

        <!--    logout:退出登录
                logout-url:退出登录操作采采芣苡的请求路径
                logout-success-url:退出登录后的跳转页面

                基于过滤器实现
        -->
        <security:logout logout-url="/logout.do"
                         logout-success-url="/login.html"
                         invalidate-session="true"/>
    </security:http>

    <!--    配置认证管理器-->
    <security:authentication-manager>
        <!--        配置认证提供者-->
        <security:authentication-provider user-service-ref="springSecurityUserService">
            <!--            指定对密码加密的对象-->
            <security:password-encoder ref="passwordEncoder"></security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>

    <!--    配置密码加密对象-->
    <bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" id="passwordEncoder"></bean>

    <!--    开启注解方式权限控制-->
    <security:global-method-security pre-post-annotations="enabled"/>

    <bean class="com.ybb.ex.MyExceptionAdvice" id="myExceptionAdvice"/>

</beans>

再写个类实现UserDetailsService接口

package com.ybb.service;

import com.alibaba.dubbo.config.annotation.Reference;
import com.ybb.pojo.Permission;
import com.ybb.pojo.Role;
import com.ybb.pojo.User;
import com.ybb.service.UserService;
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.stereotype.Component;

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

@Component
public class SpringSecurityUserService implements UserDetailsService {
    //使用dubbo通过网络远程调用服务提供方获取数据库中的用户信息
    @Reference
    private UserService userService;

    //根据用户名查询数据库获取用户信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.findByUserName(username);
        if(user == null){
            //用户名不存在
            return null;
        }
        List<GrantedAuthority> list = new ArrayList<>();
        //动态为当前用户授权
        Set<Role> roles = user.getRoles();
        for (Role role : roles) {
            //遍历角色集合,为用户授予角色
            list.add(new SimpleGrantedAuthority(role.getKeyword()));
            Set<Permission> permissions = role.getPermissions();
            for (Permission permission : permissions) {
                //遍历权限集合,为用户授权
                list.add(new SimpleGrantedAuthority(permission.getKeyword()));
            }
        }
        org.springframework.security.core.userdetails.User securityUser = new org.springframework.security.core.userdetails.User(username,user.getPassword(),list);
        return securityUser;
    }
}

在这里插入图片描述
这里踩了个坑,配置了成功的访问路径,但一直出问题,后面发现在web.xml中配置了个spring-redis和spring-security,出现了问题,不能这么配置,不规范

在这里插入图片描述
后面改动了工程,在springmvc中引入了这两个xml文件,就好了。注意配置规范

在这里插入图片描述
在这里插入图片描述

1.2controller,service,dao

在这里插入图片描述

这里因为涉及到动态的加载权限,要访问数据库,也涉及到多表联查,这里用的方式是用java代码简化xml配置的思路,根据id查询中间表,再移动到role,这是一块,后面再根据role的id查询中间表到permssion,又刚好pojo实体类中,user中有一个属性包含role的集合,role中又包含permission的集合,所以就简单了

userSerivce

public interface UserService {

      User findByUserName(String username);
}

userSericeImpl

@Service(interfaceClass = UserService.class)
@Transactional
public class UserServiceImpl implements UserService {

     @Autowired
     private UserDao userDao;

     @Autowired
     private RoleDao roleDao;

     @Autowired
     private PermissionDao permissionDao;
     //根据用户名查询书库获取用户信息和关联的角色信息,同时需要查询角色关联的权限信息

    @Autowired
    private MenuDao menuDao;

    @Override
    public User findByUserName(String username) {
        User user = userDao.findByUserName(username);
        if (user==null){
            return null;
        }
        Integer userId = user.getId();
        //根据用户ID查询对应的角色
        Set<Role> roles = roleDao.findByUserId(userId);
        for (Role role : roles) {
            //角色ID,去查询关联权限
            Integer roleId = role.getId();
            Set<Permission> permissions = permissionDao.findByRoleId(roleId);
            role.setPermissions(permissions);
        }
        user.setRoles(roles);
        return user;
    }

userDao

public interface UserDao {
    User findByUserName(String username);
}

<?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.ybb.dao.UserDao">
    -->
    <select id="findByUserName" resultType="com.ybb.pojo.User" parameterType="string">
        SELECT * FROM t_user where username=#{username}
    </select>
</mapper>

RoleDao

public interface RoleDao {
  Set<Role>findByUserId(Integer userId);
}
<?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.ybb.dao.RoleDao">
    <select id="findByUserId" resultType="com.ybb.pojo.Role" parameterType="int">
        SELECT r.* FROM t_user_role ur,t_role r where
        ur.role_id=r.id and
        ur.user_id=#{userId}
    </select>
    </mapper>

包扫描记得动一下

<!--批量扫描--> <dubbo:annotation package="com.全局" />

1.3权限

这里用注解的方式实现权限的给予

 @PreAuthorize("hasAuthority('CHECKITEM_DELETE')")//权限校验
    @RequestMapping("/delete")
    public Result delete(Integer id){
        try {
            checkItemService.deleteById(id);
        }catch (Exception e){
            return new Result(false,MessageConstant.DELETE_CHECKGROUP_FAIL);
        }
        return new Result(true, MessageConstant.DELETE_CHECKGROUP_SUCCESS);
    }

权限和角色是有层级关系的,但对于spring来说都只是个字符串而已,当要涉及到角色或者权限验证的时候,就去这个集合中找有没有这个字符串,没有就403.

List<GrantedAuthority> list = new ArrayList<>();

1.4 403时如何处理给用户看

spring这有个接口AccessDeniedHandler,专门处理403情况的,不过也算个异常,自己可以写个异常处理器来实现。这里博主比较懒,基于spring框架来实现的。

package com.ybb.ex;

import com.alibaba.fastjson.JSON;
import com.ybb.entity.Result;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

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

/**
 * Description :spring security内部封装了权限出问题的异常处理器,如果出异常就会跑这来
 * Version :1.0
 */
public class MyExceptionAdvice implements AccessDeniedHandler {


    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        Result result = new Result(false,"出问题啦");
        String data = JSON.toJSON(result).toString();
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().print(data);
    }
}

然后配置进spring-security中,注意插入位置

在这里插入图片描述

1.5显示用户名

前面我们已经完成了认证和授权操作,如果用户认证成功后需要在页面展示当前用户的用户名。Spring
Security在认证成功后会将用户信息保存到框架提供的上下文对象中,所以此处我们就可以调用Spring
Security框架提供的API获取当前用户的username并展示到页面上。
实现步骤:
第一步:在main.html页面中修改,定义username模型数据基于VUE的数据绑定展示用户名,发送ajax
请求获取username

 new Vue({
        el: '#app',
        data: {
            username: null,
            },
            created(){
            axios.get("/user/getUsernameAndMenu.do").then((res)=>{
                if (res.data.flag){
                    this.username=res.data.data.username
                }
            })
        },
package com.ybb.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.ybb.constant.MessageConstant;
import com.ybb.entity.Result;
import com.ybb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.swing.*;

/**
 * Description :
 * Version :1.0
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Reference
    private UserService userService;

    //获得当前登录用户的用户名
    @RequestMapping("/getUsernameAndMenu")
    public Result getUsername(){
        //当spring security完成认证后,会将当前用户信息保存到框架提供的上下文对象(基于session)
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        System.out.println(user);
        if (user!=null){
            return new Result(true, MessageConstant.GET_MENU_SUCCESS,user.getUsername);
        }
       return new Result(false,MessageConstant.GET_USERNAME_FAIL);
    }
}

在这里插入图片描述

1.6 用户退出

在这里插入图片描述
在这里插入图片描述

a标签加security配置,结束

2. 图形报表ECharts

2.1 ECharts简介

ECharts缩写来自Enterprise Charts,商业级数据图表,是百度的一个开源的使用JavaScript实现的数据
可视化工具,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,
Chrome,Firefox,Safari等),底层依赖轻量级的矢量图形库 ZRender,提供直观、交互丰富、可高
度个性化定制的数据可视化图表

https://echarts.apache.org/examples/zh/index.html

下载什么的就不说了。只需要引入echarts.js文件就能用了

2.2会员数量折线图

2.21 需求分析

会员信息是体检机构的核心数据,其会员数量和增长数量可以反映出机构的部分运营情况。通过折线图
可以直观的反映出会员数量的增长趋势。本章节我们需要展示过去一年时间内每个月的会员总数据量。
展示效果如下图:
在这里插入图片描述

2.22 完善页面

记得引入echats.js文件

<!DOCTYPE html>
<html>
    <head>
        <!-- 页面meta -->
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>传智健康</title>
        <meta name="description" content="传智健康">
        <meta name="keywords" content="传智健康">
        <meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
        <!-- 引入样式 -->
        <link rel="stylesheet" href="../css/style.css">
        <script src="../plugins/echarts/echarts.js"></script>
    </head>
    <body class="hold-transition">
        <div id="app">
            <div class="content-header">
                <h1>统计分析<small>会员数量</small></h1>
                <el-breadcrumb separator-class="el-icon-arrow-right" class="breadcrumb">
                    <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
                    <el-breadcrumb-item>统计分析</el-breadcrumb-item>
                    <el-breadcrumb-item>会员数量</el-breadcrumb-item>
                </el-breadcrumb>
            </div>
            <div class="app-container">
                <div class="box">
                    <!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
                    <div id="chart1" style="height:600px;"></div>
                </div>
            </div>
        </div>
    </body>
    <!-- 引入组件库 -->
    <script src="../js/vue.js"></script>
    <script src="../js/axios-0.18.0.js"></script>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart1 = echarts.init(document.getElementById('chart1'));

        // 使用刚指定的配置项和数据显示图表。
        //myChart.setOption(option);

        axios.get("/report/getMemberReport.do").then((res)=>{
            myChart1.setOption(
                                {
                                    title: {
                                        text: '会员数量'
                                    },
                                    tooltip: {},
                                    legend: {
                                        data:['会员数量']
                                    },
                                    xAxis: {
                                        data: res.data.data.months
                                    },
                                    yAxis: {
                                        type:'value'
                                    },
                                    series: [{
                                        name: '会员数量',
                                        type: 'line',
                                        data: res.data.data.memberCount
                                    }]
                                });
        });
    </script>
</html>

2.23 后台代码

这里实现的业务逻辑是比如第一个月1个,第二个月加了2个,展示的3,累加的效果。

package com.ybb.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.ybb.constant.MessageConstant;
import com.ybb.entity.Result;
import com.ybb.service.MemberService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Description :
 * Version :1.0
 */
@RestController
@RequestMapping("/report")
public class report {

    @Reference
    private MemberService memberService;

    @RequestMapping("/getMemberReport")
    public Result getMemberReport() {
        //需要往前端传两个数组对象,用map封装
        HashMap<String, Object> map = new HashMap<>();
        List<String> months = new ArrayList<>();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
        //先要计算过去一年的12个月
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, -12);
        for (int i = 0; i < 12; i++) {
            calendar.add(Calendar.MONTH, 1);
            months.add(format.format(calendar.getTime()));
        }
        map.put("months",months);

        List<Integer> memberCountByMonths = memberService.findMemberCountByMonths(months);
        map.put("memberCount",memberCountByMonths);
        return new Result(true, MessageConstant.GET_MEMBER_NUMBER_REPORT_SUCCESS,map);
    }


}

MemberService

List<Integer>findMemberCountByMonths(List<String>months);

MemberServiceImpl

package com.ybb.service.Impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.ybb.dao.MemberDao;
import com.ybb.pojo.Member;
import com.ybb.service.MemberService;
import com.ybb.utils.MD5Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * Description :
 * Version :1.0
 */
@Service(interfaceClass = MemberService.class)
@Transactional
public class MemberServiceImpl implements MemberService {

    @Autowired
    private MemberDao memberDao;

    //根据月份查询会员数量
    @Override
    public List<Integer> findMemberCountByMonths(List<String> months) {
        List<Integer>memberCount=new ArrayList<>();
        for (String month : months) {
            String date = month + ".31";
            Integer memberCountBeforeDate = memberDao.findMemberCountBeforeDate(date);
            memberCount.add(memberCountBeforeDate);
        }
        return memberCount;
    }
}

dao

 public Integer findMemberCountBeforeDate(String date);
    <!--根据日期统计会员数,统计指定日期之前的会员数-->
    <select id="findMemberCountBeforeDate" parameterType="string" resultType="int">
        select count(id) from t_member where regTime &lt;= #{value}
    </select>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security是一个功能强大的身份验证和访问控制框架,用于保护Java应用程序的安全性。它提供了一套全面的安全性解决方案,包括身份验证、授权、密码管理和会话管理等功能。 Spring Security权限控制是通过以下几个核心概念来实现的: 1. 认证(Authentication):认证是验证用户身份的过程。Spring Security支持多种认证方式,包括基于表单、基于HTTP基本认证、基于LDAP等。在认证成功后,Spring Security会将用户的身份信息存储在一个称为SecurityContext的地方,以便后续的授权操作使用。 2. 授权(Authorization):授权是确定用户是否有权限执行某个操作的过程。Spring Security提供了一套灵活的授权机制,可以通过注解、表达式、配置文件等方式进行权限控制。常见的授权方式包括基于角色(Role-based)和基于资源(Resource-based)的授权。 3. 权限(Permission):权限是指用户被授予的特定操作或资源访问的能力。Spring Security支持细粒度的权限控制,可以通过配置角色和权限之间的关系来实现。 4. 过滤器链(Filter Chain):Spring Security通过一系列的过滤器链来处理请求。每个过滤器负责不同的安全功能,例如身份验证、授权、会话管理等。过滤器链的配置可以通过Java配置或XML配置来完成。 5. 安全注解(Security Annotation):Spring Security提供了一系列的注解,用于在方法或类级别上进行权限控制。例如,@PreAuthorize注解可以在方法执行前进行权限检查,如果不满足条件则拒绝访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值