(B站云e办)SpringBoot开发项目实战记录(三)(用户角色判断、url判断角色、职位管理crud)

一、 根据请求的url判断角色

1.1 业务层Service

首先要拿到每个菜单对应的角色

/**
     * 根据角色查菜单
     * @return
     */
    @Override
    public List<Menu> getMenusWithRole() {
        return menuMapper.getMenusWithRole();
    }

1.2 mapper层

1. 查询的xml

<!--根据角色获取菜单列表-->
    <select id="getMenusWithRole" resultMap="MenusWithRole">
        SELECT
        m.*,
        r.id as rid,
        r.`name` as rname,
        r.nameZh AS rnameZh
        FROM t_menu m,
        t_menu_role mr,
        t_role r
        WHERE
        m.id = mr.id
        AND
        mr.rid = r.id
        ORDER BY m.id
    </select>

2. 返回格式map (MenusWithRole)

<resultMap id="MenusWithRole" type="com.jzq.server.pojo.Menu" extends="BaseResultMap">
        <collection property="roles" ofType="com.jzq.server.pojo.Role">
            <id column="rid" property="id"></id>
            <result column="rname" property="name"></result>
            <result column="rnameZh" property="nameZh"></result>
        </collection>
    </resultMap>

3. url匹配权限过滤器

⭐知识点:

  1. 用于匹配的Spring类:AntPathMatcher antPathMatcher = new AntPathMatcher();
    根据获取请求的url和菜单列表的url对比:antPathMatcher.match(requestUrl, menu.getUrl())
  2. 如果匹配到,就把能用这个路径的角色放到数据返回
    String[] strArray = menu.getRoles().stream().map(Role::getName).toArray(String[]::new);
    return SecurityConfig.createList(strArray);
/**
 * 权限控制
 * 根据请求url,分析请求所需角色
 */
public class CustomFilter implements FilterInvocationSecurityMetadataSource {

    @Autowired
    private IMenuService menuService;

    // 匹配url的实例
    AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
        // 获取请求的Url
        String requestUrl = ((FilterInvocation) o).getRequestUrl();
        System.out.println("requestUrl"+requestUrl);

        // 获取菜单信息
        List<Menu> menuList = menuService.getMenusWithRole();
        System.out.println("menuList"+menuList);

        System.out.println("--------------------------");
        for (Menu menu : menuList) {
            // 逐个与url进行匹配
            if (antPathMatcher.match(menu.getUrl(),requestUrl)){
                // 如果匹配成功(把这个路径对应的角色封装到一个数组)
                String[] strArray = menu.getRoles().stream().map(Role::getName).toArray(String[]::new);
                return SecurityConfig.createList(strArray);
            }
        }
        // 如果匹配不上,就默认返回登录权限的路径
        return SecurityConfig.createList("ROLE_LOGIN");
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return false;
    }
}

二、后端判断用户角色

2.1 pojo层内Admin加入角色字段

 @ApiModelProperty(value = "角色")
    @TableField(exist = false)
    private List<Role> roles;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authorities = roles.stream().map(role -> new SimpleGrantedAuthority(role.getName())).collect(Collectors.toList());
        return authorities;
    }

2.2 service层

/**
     * 根据用户id获取角色权限
     * @param adminId
     * @return
     */
    @Override
    public List<Role> getRoles(Integer adminId) {
        return roleMapper.getRoles(adminId);
    }

2.3 mapper层

 <select id="getRoles" resultType="com.jzq.server.pojo.Role">
        SELECT
        r.id,
        r.`name`,
        r.nameZh
        FROM t_admin_role AS ar
        LEFT JOIN t_role AS r ON ar.rid = r.id
        where ar.adminId = #{adminId}
    </select>

2.4 后端验证权限过滤器

package com.jzq.server.config.custom;


import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.Collection;

/**
 *  权限控制
 *  判断用户角色
 */
@Component
public class CustomUrlDecisionManger implements AccessDecisionManager {
    @Override
    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
        for (ConfigAttribute configAttribute : collection) {
            // 当前url所需要的角色
            String needRole = configAttribute.getAttribute();
            // 判断角色是否登录即可访问的角色,此角色在CustomFilter中设置
            if("ROLE_LOGIN".equals(needRole)) {
                // 判断是否登录了
                if(authentication instanceof AnonymousAuthenticationToken) {
                    throw new AccessDeniedException("尚未登录,请登录");
                }else {
                    return;
                }
            }

            // 判断角色是否为url所需要的角色
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                if (authority.getAuthority().equals(needRole)) {
                    return;
                }
            }
        }

        throw new AccessDeniedException("权限不足,请联系管理!");
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return false;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return false;
    }
}

2.5 把过滤器设置到security配置类中


 @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 使用JWT,不需要csrf
        http.csrf()
                // 禁用csrf
                .disable()
                // 基于token, 不需要session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 允许登录访问
                //.antMatchers("/login", "/logout")
                //.permitAll()
                // 除了上面的请求,其他的都要认证
                .anyRequest()
                .authenticated()
                // 动态权限配置
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setAccessDecisionManager(customUrlDecisionManger);
                        o.setSecurityMetadataSource(customFilter);
                        return o;
                    }
                })
                .and()
                // 禁用缓存
                .headers()
                .cacheControl();

}

在这里插入图片描述

三、职位管理功能

3.1 pojo实体类

⭐知识点:
@JsonFormat(pattern = “yyyy-MM-dd”, timezone = “Asia/Shanghai”)
从数据库获取日期类型,通过使用@JsonFormat可以很好的解决后台到前台时间格式转换(时间戳到格式化日期字符串),pattern:是你需要转换的时间日期的格式,timezone:是时间设置为东八区,避免时间在转换中有误差前端


@DateTimeFormat(pattern = "yyyy-MM-dd") 传给后端存库时可以使用@DataTimeFormat便很好的解决了这个问题,接下来记录一下具体的@JsonFormat与DateTimeFormat的使用过程。
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai")
private LocalDateTime createDate;

3.2 职位管理Controller(通过MybatisPlus操作)

⭐知识点:

  1. @Autowired
    private IPositionService positionService; 注入service
  2. 一些MybatisPlus方法的使用:
    1.获取所有记录:positionService.list()
    2.增加一条记录:positionService.save(position)
    3.更新一条记录:positionService.updateById(position)
    4.删除一条记录:positionService.removeById(id)
    5.删除一组记录:positionService.removeByIds(Arrays.asList(ids))
/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author seven
 * @since 2022-01-02
 */
@RestController
@Api(tags = "职位管理接口")
@RequestMapping("/api/system/config/pos")
public class PositionController {

    @Autowired
    private IPositionService positionService;


    @ApiOperation(value = "获取所有职位信息")
    @GetMapping("/")
    public List<Position> getAllPosition() {
        // MybatisPlus的方法,获取所有记录
        return positionService.list();
    }

    @ApiOperation(value = "增加一个职位")
    @PostMapping("/")
    public RespBean addPosition(@RequestBody Position position) {
        position.setCreateDate(LocalDateTime.now());
        // MybatisPlus的方法,增加一条记录
        if(positionService.save(position)) {
            return RespBean.success("增加职位成功");
        }
        return RespBean.warning("增加职位失败");
    }

    @ApiOperation(value = "修改职位")
    @PutMapping("/")
    public RespBean updatePosition(@RequestBody Position position){
        // MybatisPlus的方法,修改一条记录
        if (positionService.updateById(position)) {
            return RespBean.success("修改职位信息成功");
        }
        return RespBean.warning("修改职位信息失败");
    }

    @ApiOperation(value = "删除一个职位信息")
    @DeleteMapping("/{id}")
    public RespBean deletePosition(@PathVariable Integer id) {
        if(positionService.removeById(id)) {
            return RespBean.success("删除一个职位成功");
        }
        return RespBean.warning("删除一个职位失败");
    }

    @ApiOperation(value = "删除一组职位信息")
    @DeleteMapping("/")
    public RespBean deletePositions(Integer[] ids) {
        if(positionService.removeByIds(Arrays.asList(ids))) {
            return RespBean.success("删除一组职位成功");
        }
        return RespBean.error("删除一组职位失败");
    }
}

示例:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值