Shiro安全框架与SpringBoot的整合(下)

news2024/11/20 12:40:58

目录

一、整合前的配置

1.1 导入shiro依赖

1.2 config配置

1.2.1 ShiroConfig(⭐)

 1.2.2 MyConfig(拦截器配置)

 3. 拦截器(LoginInterceptor)

二、认证登录

2.1. controller

2.2 service和serviceImpl(不用)

2.3 mapper

2.4 自定义的shiro和realm

三、权限授权验证

3.1. controller(测试接口的权限)

3.2 自定义的shiro和realm

四、动态菜单的实现

4.1 目标效果

4.2  查询所有的权限

4.3 不同的用户显示不同的菜单(权限)


一、整合前的配置

1.1 导入shiro依赖

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

1.2 config配置

1.2.1 ShiroConfig(⭐)

配置shiro的一些基本配置,需要注意--设置安全管理器securityManager与你的项目有关,

这里我设置了登录时需要的自定义myRealm,和权限授权验证前的自定义uuidRealm。

package com.itqq.config;

import com.itqq.realm.MyRealm;
import com.itqq.realm.UUIDRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

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

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: sys
 * @Description:shiro整合Spring的配置文件
 */
@Configuration
public class ShiroConfig {
    @Autowired
    private MyRealm myRealm;
    @Autowired
    private UUIDRealm uuidRealm;

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
    @Bean(name = "lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(securityManager());
        return new AuthorizationAttributeSourceAdvisor();
    }
    // 设置安全管理器securityManager
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        List<Realm> realms = new ArrayList<>();
        realms.add(myRealm);
        realms.add(uuidRealm);
        securityManager.setRealms(realms);
        return securityManager;
    }
    // 设置filter
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(){
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager( securityManager());
        shiroFilter.setLoginUrl("/anon");
        shiroFilter.setUnauthorizedUrl("/anon");
        return shiroFilter;
    }
//    @Bean
//    public MyRealm myRealm(){
//        return new MyRealm();
//    }
}
 1.2.2 MyConfig(拦截器配置)

因为每次权限验证前都需要验证该账号是否登录,所以使用拦截器

package com.itqq.config;

import com.itqq.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: syq
 * @Description:
 */
@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
//        将loginInterceptor这个拦截器注册到Spring Boot中,并排除对/employee/login(登录)这个路径的拦截
        registry.addInterceptor(loginInterceptor).excludePathPatterns("/employee/login");
    }
}

 3. 拦截器(LoginInterceptor)

将重复的代码抽取出来,此时,用户已经登录过一次,需要再次认证

package com.itqq.interceptor;

import com.itqq.shiro.UUIDToken;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: syq
 * @Description:使用过滤器用户在进行权限验证时必须要先认证,一个个加太麻烦
 * 所以在拦截器中统一进行认证
 *
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            String token = request.getHeader("token");
//            使用Shiro框架的SecurityUtils.getSubject()方法获取当前的Subject(即用户身份)
            Subject subject = SecurityUtils.getSubject();
//            将token传给UUIDRealm进行认证
            subject.login(new UUIDToken(token));
        }catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }
}

二、认证登录

使用shiro框架自带的组件进行登录验证,不用用户的service和serviceImpl

2.1. controller

package com.itqq.controller;

import com.itqq.pojo.Employee;
import com.itqq.pojo.Result;
import com.itqq.service.EmployeeService;
import com.itqq.shiro.PhonePasswordToken;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: syq
 * @Description:
 */
@RestController
@RequestMapping("employee")
public class EmployeeController {
    @Autowired
    private EmployeeService employeeService;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 登录接口
     * @param token
     * @return
     */
    @PostMapping("login")
    public Result login(@RequestBody PhonePasswordToken token) {
//        此token是前端传来的登录信息,这里是phone和password
        SecurityUtils.getSubject().login(token);
        String tokenString = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(tokenString, SecurityUtils.getSubject().getPrincipal());
        return Result.success(tokenString);
    }
    @GetMapping("")
    public Result findAll() {
        return Result.success(employeeService.findAll());
    }
    @GetMapping("findById/{id}")
    public Result findById(@PathVariable Integer id) {
        return Result.success(employeeService.findById(id));
    }
    /**
     * 添加员工
     * @param employee
     * @return
     */
    @PostMapping("add")
    public Result add(@RequestBody Employee employee) {
        return employeeService.add(employee) ? Result.success("添加成功") : Result.failed("添加失败");
    }
    @PostMapping("update")
    public Result update(@RequestBody Employee employee) {
        return employeeService.update(employee) ? Result.success("修改成功") : Result.failed("修改失败");
    }
    @DeleteMapping("delete")
    public Result delete(Integer id) {
        return employeeService.delete(id) ? Result.success("删除成功") : Result.failed("删除失败");
    }
    @DeleteMapping("deleteids")
    public Result deleteids(Integer[] ids) {
        return employeeService.deleteids(ids) ? Result.success("删除成功") : Result.failed("删除失败");
    }
}

2.2 service和serviceImpl(不用)

package com.itqq.service;

import com.itqq.pojo.Employee;
import com.itqq.pojo.Result;

import java.util.List;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: syq
 * @Description:
 */
public interface EmployeeService {

    List<Employee> findAll();

    Employee findById(Integer id);

    boolean add(Employee employee);

    boolean update(Employee employee);

    boolean delete(Integer id);

    boolean deleteids(Integer[] ids);

    Employee findEmployeeByName(String name);

    Employee findEmployeeByPhone(Long phone);
}

增加用户信息的时候,密码进行MD5加密 ,盐是动态盐

package com.itqq.service.impl;


import com.itqq.mapper.EmployeeMapper;
import com.itqq.pojo.Employee;
import com.itqq.service.EmployeeService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: syq
 * @Description:
 */
@Service
public class EmployeeServiceImpl implements EmployeeService {
    @Autowired
    private EmployeeMapper employeeMapper;

    @Override
    public List<Employee> findAll() {
        return employeeMapper.findAll();
    }

    @Override
    public Employee findById(Integer id) {
        return employeeMapper.findById(id);
    }

    @Override
    public boolean add(Employee employee) {
//      添加的时候设置动态盐
        String slat = UUID.randomUUID().toString().replace("-", "");
//        密码加密存储
        String password = String.valueOf(new SimpleHash("MD5", employee.getPassword(), slat, 1024));
//        获取当前登录人的id
        Integer principal = (Integer) SecurityUtils.getSubject().getPrincipal();
        employee.setPassword(password);
        employee.setSalt(slat);
        employee.setCreateTime(new Date());
        employee.setCreateId(principal);
        return employeeMapper.add(employee);
    }

    @Override
    public boolean update(Employee employee) {
        return employeeMapper.update(employee);
    }

    @Override
    public boolean delete(Integer id) {
        return employeeMapper.delete(id);
    }

    @Override
    public boolean deleteids(Integer[] ids) {
        return employeeMapper.deleteids(ids);
    }

    @Override
    public Employee findEmployeeByName(String name) {
        return employeeMapper.findEmployeeByName(name);
    }

    @Override
    public Employee findEmployeeByPhone(Long phone) {
        return employeeMapper.findEmployeeByPhone(phone);
    }
}

2.3 mapper

package com.itqq.mapper;

import com.itqq.pojo.Employee;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: syq
 * @Description:
 */
public interface EmployeeMapper {
    List<Employee> findAll();

    Employee findById(Integer id);

    boolean add(Employee employee);

    boolean update(Employee employee);

    boolean delete(Integer id);

    boolean deleteids(Integer[] ids);

    Employee findEmployeeByName(String name);

    Employee findEmployeeByPhone(Long phone);
}
<?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.itqq.mapper.EmployeeMapper">
    <insert id="add">
        insert into sys_employee(name,password,phone,salt,status,create_id,create_time)
        values(#{name},#{password},#{phone},#{salt},#{status},#{createId},#{createTime})
    </insert>
    <update id="update">
        update sys_employee
        <set>
            <if test="name != null">
                name = #{name},
            </if>
            <if test="password != null">
                password = #{password},
            </if>
            <if test="phone != null">
                phone = #{phone},
            </if>
            <if test="salt != null">
                salt = #{salt},
            </if>
            <if test="status != null">
                status = #{status},
           </if>
            <if test="createId != null">
                create_id = #{createId},
            </if>
            <if test="createTime != null">
                create_time = #{createTime},
            </if>
        </set>
    </update>
    <delete id="delete">
        delete from sys_employee where id = #{id}
    </delete>
    <delete id="deleteids">
        delete from sys_employee where id in
        <foreach collection="ids" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>
    <select id="findAll" resultType="com.itqq.pojo.Employee">
        select * from sys_employee
    </select>
    <select id="findById" resultType="com.itqq.pojo.Employee">
        select * from sys_employee where id = #{id}
    </select>
    <select id="findEmployeeByName" resultType="com.itqq.pojo.Employee">
        select * from sys_employee where name = #{name}
    </select>
    <select id="findEmployeeByPhone" resultType="com.itqq.pojo.Employee">
        select * from sys_employee where phone = #{phone}
    </select>
</mapper>

2.4 自定义的shiro和realm

package com.itqq.realm;

import com.itqq.pojo.Employee;
import com.itqq.service.EmployeeService;
import com.itqq.shiro.PhonePasswordToken;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: syq
 * @Description:自定义的MyRealm用于认证使用
 */
@Component
public class MyRealm extends AuthorizingRealm {
    @Autowired
    private EmployeeService employeeService;
    public MyRealm() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        hashedCredentialsMatcher.setHashIterations(1024);
        this.setCredentialsMatcher(hashedCredentialsMatcher);
    }
//    判断传入的AuthenticationToken对象是否是PhonePasswordToken类型的实例
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof PhonePasswordToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
//    认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("-----------------开始认证!!!!");
//        接收用户输入的账号(手机号)和密码
        Long phone = (Long) token.getPrincipal();
        String password = (String) token.getCredentials();
        if(phone == null){
            throw new AuthenticationException("账号不能为空");
        }
        if(!StringUtils.hasText(password)){
            throw new AuthenticationException("密码不能为空");
        }
//        从数据库中查询对象
        Employee employee = employeeService.findEmployeeByPhone(phone);
        if(employee == null){
            throw new AuthenticationException("用户名不存在");
        }
        System.out.println(employee.getSalt());
        System.out.println(employee.getName());
        System.out.println(employee.getPassword());
        return new SimpleAuthenticationInfo(employee.getId(),employee.getPassword(),ByteSource.Util.bytes(employee.getSalt()),getName());
    }
}

自定义的shiro组件接收 前端传来的登录信息

package com.itqq.shiro;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.shiro.authc.AuthenticationToken;

import java.io.Serializable;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: syq
 * @Description:
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PhonePasswordToken implements AuthenticationToken, Serializable {
    private static final long serialVersionUID = -240712713650948393L;
    private Long phone;
    private String password;

    @Override
    public Object getPrincipal() {
        return phone;
    }

    @Override
    public Object getCredentials() {
        return password;
    }
}

三、权限授权验证

认证之后,每次权限验证前需要再次进行登录验证(具体配置见config拦截器配置)

3.1. controller(测试接口的权限)

package com.itqq.controller;

import com.itqq.pojo.Result;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author:syq
 * @Description:授权测试
 */
@RestController
@RequestMapping("welcome")
public class WelcomeController {
     /*
        1. 游客接口
        2. 认证接口
        3. 游客/认证接口
        4. 授权接口
     */
     @GetMapping("1.do")
     public Result m1(){
         return Result.success("1.游客接口!!!");
     }
//    @RequiresUser需要用户认证才能访问的方法或类,要token
    @RequiresUser
    @GetMapping("2.do")
    public Result m2(/*@RequestHeader String token*/){
        Subject subject = SecurityUtils.getSubject();
//        subject.login(new UUIDToken(token));
        return Result.success("2.认证接口!!!" +  subject.getPrincipals());
    }
    @RequestMapping("3.do")
    public Result m3(){
        Subject subject = SecurityUtils.getSubject();
        if(subject.isAuthenticated()){
            return Result.success("3.认证接口!!!" + subject.getPrincipals());
        }else{
            return Result.failed("3.游客接口!!!");
        }
    }
//    @RequiresRoles注解,表示该接口需要在具有特定角色的用户才能访问
    @RequiresRoles("管理员")
    @RequestMapping("4.do")
    public Result m4(){
        Subject subject = SecurityUtils.getSubject();
        return Result.success("4-1.授权角色接口" +  subject.getPrincipals());
    }
    @RequiresPermissions("sys:employee:insert")
    @RequestMapping("5.do")
    public Result m5(){
        Subject subject = SecurityUtils.getSubject();
        return Result.success("5-2.授权权限接口" +  subject.getPrincipals());
    }
    //    @RequiresRoles({"管理员","管理员2"})--两个角色都要满足
    @RequiresRoles(value = {"管理员","超级管理员"},logical = Logical.OR)//只用满足一个条件
    @RequestMapping("6.do")
    public Result m6(){
        Subject subject = SecurityUtils.getSubject();
        return Result.success("6-2.授权权限接口" +  subject.getPrincipals());
    }
}

service和serviceImpl和上述一样这里就不在赘述 

3.2 自定义的shiro和realm

 将当前账号有关的角色信息和权限信息添加到shiro组件中,用于判断

package com.itqq.realm;

import com.itqq.mapper.PermissionMapper;
import com.itqq.service.EmployeeService;
import com.itqq.service.PermissionService;
import com.itqq.service.RoleService;
import com.itqq.shiro.UUIDToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: syq
 * @Description:
 */
@Component
@Slf4j
public class UUIDRealm extends AuthorizingRealm {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permissionService;

    //用于判断传入的AuthenticationToken对象是否是UUIDToken的实例。如果是,则返回true,表示支持该令牌;否则返回false,表示不支持该令牌。
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UUIDToken;
    }
//    该函数调用了roleService.findRoleNameByEmployeeId(id)方法,
//    将返回值添加到info对象的roles属性中。
//    findRoleNameByEmployeeId方法根据员工ID查找对应的职位名称
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Integer id = (Integer) principalCollection.getPrimaryPrincipal();
        log.info("id:{}",id);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(roleService.findRoleNameByEmployeeId(id));
        info.addStringPermissions(permissionService.findPermissionNameByEmployeeId(id));
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//          从令牌中提取UUID作为凭证
        String uuid = (String) token.getCredentials();
        if(!StringUtils.hasText(uuid)){
            throw new RuntimeException("token不能为空");
        }
//        从resdis中获取员工id
        Integer id = (Integer)redisTemplate.opsForValue().get(uuid);
        if(id == null){
            throw new RuntimeException("token已经失效");
        }
//        构建认证信息对象,包含用户ID、UUID和名称
//        将员工id,uuid(生成的),名称送去校验
        return new SimpleAuthenticationInfo(id,uuid,getName());
    }
}
package com.itqq.shiro;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.shiro.authc.AuthenticationToken;

import java.io.Serializable;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: syq
 * @Description:
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UUIDToken implements AuthenticationToken, Serializable {
    private static final long serialVersionUID = 8884806189738587998L;
    private String uuid;
    @Override
    public Object getPrincipal() {
        return uuid;
    }

    @Override
    public Object getCredentials() {
        return uuid;
    }
}

四、动态菜单的实现

4.1 目标效果

 

 数据库设计

动态菜单需要根据查看用户的所有权限,主要是要进行树状显示查询

4.2  查询所有的权限

1. Controller


//    查询全部数据
    List<Permission> findByParentId(Integer id);

2. service和serviceImpl

    List<Permission> findAll();
    public List<Permission> findAll() {
        return permissionMapper.findByParentId(0);
    }

3. mapper

//    查询全部数据
    List<Permission> findByParentId(Integer id);

先运行findByParentId,运行一次后,结果映射又递归调用此时将id赋值parentId 

 <resultMap id="permission" type="Permission">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="path" property="path"/>
        <result column="permission" property="permission"/>
        <result column="icon" property="icon"/>
        <result column="parent_id" property="parentId"/>
        <result column="create_id" property="createId"/>
        <result column="create_time" property="createTime"/>
        <result column="index" property="index"/>
        <collection property="children" ofType="Permission" select="findByParentId" column="id"></collection>
    </resultMap>
    <select id="findByParentId" resultMap="permission">
        select * from sys_permission where parent_id = #{parentId}
    </select>

4.3 不同的用户显示不同的菜单(权限)

1. controller

//    获取当前用户的菜单
    @RequiresUser
    @GetMapping("menu")
    public Result findMenu(){
        return Result.success(permissionService.findMenu());
    }

2. service和serviceImpl

List<Permission> findMenu(
public List<Permission> findMenu() {
        Integer eid = (Integer) SecurityUtils.getSubject().getPrincipal();
        return permissionMapper.findMenu(eid, 0);
    }

3. mapper

//    根据不同的用户查询数据
    List<Permission> findMenu(@Param("eid") Integer eid,@Param("parentId") Integer parentId);
<resultMap id="permission1" type="Permission">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="path" property="path"/>
        <result column="permission" property="permission"/>
        <result column="icon" property="icon"/>
        <result column="parent_id" property="parentId"/>
        <result column="create_id" property="createId"/>
        <result column="create_time" property="createTime"/>
        <result column="index" property="index"/>
        <collection property="children" ofType="Permission" select="findMenu" column="{eid=eid,parentId=id}"></collection>
    </resultMap>
    <select id="findMenu" resultMap="permission1">
        SELECT DISTINCT p.*,eid from sys_permission p
                                LEFT JOIN sys_role_permission rp on p.id = rp.pid
                                LEFT JOIN sys_employee_role er on er.rid = rp.rid
        where eid = #{eid} and parent_id = #{parentId} and permission is null
        order by p.index asc
    </select>

4. pojo

@Data
public class Permission implements Serializable {
    private static final long serialVersionUID = -9189388242103298381L;
    private Integer id;
    private String name;
    private String permission;
    private String path;
    private String icon;
    private Integer parentId;
    private Integer createId;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Timestamp createTime;
    private Integer index;

    private List<Permission> children;
}

总结完毕!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1954815.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Meachines] [Easy] Blocky Jar包反编译

信息收集 IP AddressOpening Ports10.10.10.37TCP:21,22,80,25565 $ nmap -p- 10.10.10.37 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 21/tcp open ftp ProFTPD 1.3.5a 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu …

自动驾驶的六个级别是什么?

自动驾驶汽车和先进的驾驶辅助系统&#xff08;ADAS&#xff09;预计将帮助拯救全球数百万人的生命&#xff0c;消除拥堵&#xff0c;减少排放&#xff0c;并使我们能够在人而不是汽车周围重建城市。 自动驾驶的世界并不只由一个维度组成。从没有任何自动化到完整的自主体验&a…

VScode调试Python代码

用Python debugger 参考 vscode-python的debug 教学(最全)

动手学深度学习55 循环神经网络 RNN 的实现

动手学深度学习55 循环神经网络 RNN 的实现 从零开始实现简洁实现QA 课件&#xff1a;https://zh-v2.d2l.ai/chapter_recurrent-neural-networks/rnn-scratch.html 从零开始实现 %matplotlib inline import math import torch from torch import nn from torch.nn import fun…

【前端逆向】最佳JS反编译利器,原来就是chrome!

有时候需要反编译别人的 min.js。 比如简单改库、看看别人的 min,js 干了什么&#xff0c;有没有重复加载&#xff1f;此时就需要去反编译Javascript。 Vscode 里面有一些反编译插件&#xff0c;某某Beautify等等。但这些插件看人品&#xff0c;运气不好搞的话&#xff0c;反…

力扣高频SQL 50题(基础版)第二十题

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第二十题2356.每位教师所教授的科目种类的数量题目说明思路分析实现过程准备数据实现方式结果截图 力扣高频SQL 50题&#xff08;基础版&#xff09;第二十题 2356.每位教师所教授的科目种类的数量 题目说明 表: Te…

算法——二分查找(day10)

目录 69. x 的平方根 题目解析&#xff1a; 算法解析&#xff1a; 代码&#xff1a; 35. 搜索插入位置 题目解析&#xff1a; 算法解析&#xff1a; 代码&#xff1a; 69. x 的平方根 69. x 的平方根 - 力扣&#xff08;LeetCode&#xff09; 题目解析&#xff1a; 老…

2025第十九届中国欧亚国际军民两用技术及西安国防电子航空航天暨无人机展

2025第十九届中国欧亚国际军民两用技术及西安国防电子航空航天暨无人机展 时间&#xff1a;2025年3月14-16日 地点&#xff1a;西安国际会展中心 详询主办方陆先生 I38&#xff08;前三位&#xff09; I82I&#xff08;中间四位&#xff09; 9I72&#xff08;后面四位&am…

中间层 k8s(Kubernetes) 到底是什么,架构是怎么样的?

你是一个程序员&#xff0c;你用代码写了一个博客应用服务&#xff0c;并将它部署在了云平台上。 但应用服务太过受欢迎&#xff0c;访问量太大&#xff0c;经常会挂。 所以你用了一些工具自动重启挂掉的应用服务&#xff0c;并且将应用服务部署在了好几个服务器上&#xff0c;…

【C++】实验六

题目&#xff1a; 1、苹果和虫子 描述&#xff1a;你买了一箱n个苹果&#xff0c;很不幸的是买完时箱子里混进了一条虫子。虫子每x小时能吃掉一个苹果&#xff0c;假设虫子在吃完一个苹果之前不会吃另一个&#xff0c;那么经过y小时你还有多少个完整的苹果&#xff1f; 输入…

Linux基础复习(三)

前言 接Linux基础复习二 一、常用命令及其解释 Tab补全 在上一篇文章配置了IP然后通过远程SSH连接软件控制主机&#xff0c;在配置过程中会发现有些命令过于长&#xff0c;那么&#xff0c;Tab键补全就可以很好的帮助我们去快速的敲出命令&#xff0c;同时如果有些命令有遗…

AJAX(1)——axios库的使用

什么是AJAX? AJAX是异步的JavaScript和XML。简单来说&#xff0c;就是使用XMLHttpRequest对象与服务器通信。它可以使用JSON,XML,HTML和text文本等格式发送和接收数据。AJAX最吸引人的就是它异步的特性&#xff0c;也就是说它可以在不重新刷新页面的情况下与服务器通信&#…

免费【2024】springboot 宠物救助管理系统的设计与实现

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

成为git砖家(4): git status 命令简介

1. untracked 和 tracked 状态 Remember that each file in your working directory can be in one of two states: tracked or untracked. Tracked files are files that were in the last snapshot, as well as any newly staged files; they can be unmodified, modified, o…

Feign自定义调用第三方接口并实现负载均衡

Feign自定义调用第三方接口并实现负载均衡 Feign简介&#xff1a; Feign 是一个声明式的、模板化的HTTP客户端&#xff0c;用于简化HTTP客户端的开发。它是Spring Cloud Netflix微服务套件中的一部分&#xff0c;使得编写Java HTTP客户端变得更加容易。它的原理主要是代理模式…

Rust |了解+ 环境配置(rust+vscode)

1 了解rust 1️⃣0️⃣0️⃣秒了解Rust_哔哩哔哩_bilibili 2 安装rust 前提安装过vs&#xff0c;有c环境 1.下载 根据自己的系统下载对应的版本&#xff1a;安装地址 查看自己版本&#xff1a; 右键 此电脑 &#xff1b;点击 属性 &#xff1b;查看 系统类型 点击 下载RU…

智慧城管解决方案

1. 项目整体概述 智慧城管项目面临历史发展机遇&#xff0c;十九大提出以人为核心保障民生&#xff0c;推进新型城镇化。市民对政府服务有新诉求&#xff0c;同时云计算、物联网、移动互联网等技术迅速发展。 2. 传统城管业务模式问题 传统城管业务模式存在问题&#xff0c;…

树莓派学习记录

一&#xff0c;型号 第一代Raspberry Pi 1 Model B 第一代升级版 Raspberry Pi 1 B 第二代 Rasberry Pi 2 Model B 第三代及升级版 Rasberry Pi 3 Model B/B 第四代 Rasberry Pi 4 Model B Model A版 比B版便宜 Zero 版 售价更便宜 总结 二&#xff0c;树莓派接口 如下图…

Hello 算法:动画图解、一键运行的数据结构与算法教程

Hello 算法 《Hello 算法》是一份开源、免费的数据结构与算法入门教程&#xff0c;特别适合新手。全书采用动画图解&#xff0c;内容清晰易懂&#xff0c;学习曲线平滑&#xff0c;引导初学者探索数据结构与算法的知识地图。源代码可以一键运行&#xff0c;帮助读者通过练习提…

【教学类-70-01】20240728一个茶壶两个茶杯(果茶)

‘ 背景需求&#xff1a; 用通义万相下载简笔画茶壶、茶杯 茶杯&#xff0c;简单笔画&#xff0c;卡通&#xff0c;黑白&#xff0c;未着色&#xff0c;幼儿插图&#xff0c;线条画&#xff0c;没有背景&#xff0c;没有颜色&#xff0c;黑白漫画线条艺术:&#xff0c;空背景…