销售宝系统_Day07(权限与菜单)

  • 权限判断
  • 菜单配置

权限判断

session处理

  1. 登录成功后主体为用户
    //登录认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;

        String username = token.getUsername();
        //String password = getPassword(username);//模拟从数据库拿数据
        Employee byUsername = employeeService.findByUsername(username);
        if (byUsername==null)
            return null;
        ByteSource salt = ByteSource.Util.bytes("xpc");//获取到盐值
        				        //之前这里都是传username ,现在传byUsername   之前是用户名,现在是用户这个对象
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(byUsername, byUsername.getPassword(), salt, getName());
        return simpleAuthenticationInfo;
    }
  1. UserContext
    新建一个UserContext工具类,用来存放用户对象到session中
package com.xpc.common;

import com.xpc.domain.Employee;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;

//用户对象存session的一个工具类
public class UserContext {

    public static final String  LOGINUSER = "loginUser";

    public static void putUser(){
        //1.拿到subject(当前用户)
        Subject subject = SecurityUtils.getSubject();
        //拿到session
        Session session = subject.getSession();
        //employee这个对象
        Employee employee = (Employee)subject.getPrincipal();
        //将employee这个对象存入session中
        session.setAttribute(LOGINUSER, employee);
    }

    public static Employee getUser(){
        //获取到用户主体
        Subject subject = SecurityUtils.getSubject();
        //拿到session
        Session session = subject.getSession();
        //从session中取出数据并返回
        return (Employee)session.getAttribute(LOGINUSER);
    }
}
  1. LoginController与main.jsp
    LoginController中当用户登陆成功就调用工具类方法,把用户信息传入session中,前台在从session中获取用户信息使用
//把用户对象存入session
UserContext.putUser();


${loginUser.username}      //前台页面就可以通过session拿到用户名使用了

授权管理

  1. FilterChainDefinitionMapFactory
    保证所有权限过滤的数据都是从数据库中获取
    @Autowired
    private IPermissionService permissionService;

		...
		
        List<Permission> perms = permissionService.findAll();
        //设置相应的权限
        //这个aisellPerms要与限过滤器key一致
        perms.forEach(p -> {
            map.put(p.getUrl(), "aisellPerms["+p.getSn()+"]");
        });
  1. 获取授权
    IPermissionService

JPQL关联原则: 1.不写on 2.关联对象的别名.属性

    根据当前登录用户拿到对应的权限
    @Query("select distinct p.sn from Employee e join e.role r join r.permission p where e.id = ?1")
    Set<String> findSnByEmp(Long employeeId);

IPermissionService

Set<String> findSnByEmp(Long employeeId);

PermissionServiceImpl

    @Override
    public Set<String> findSnByEmp(Long employeeId) {
        return permissionRepository.findSnByEmp(employeeId);
    }

MyrRealm

//权限认证
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Employee employee = (Employee) principalCollection.getPrimaryPrincipal();
        
		//拿到所有权限
        Set<String> emp = permissionService.findSnByEmp(employee.getId());
        
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setStringPermissions(emp);
        return simpleAuthorizationInfo;
    }
  1. Ajax请求的权限处理
    shiro处理没有权限是跳转页面,而我们如果是ajax请求,我们希望是返回json数据 ajax请求会有一个请求头:X-Requested-With: XMLHttpRequest 需要自定义一个shiro的权限过滤器

自定义权限过滤器AisellPermissionsAuthorizationFilter

package com.xpc.web.shior;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//自定义权限过滤器
public class AisellPermissionsAuthorizationFilter extends PermissionsAuthorizationFilter {

    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {

        Subject subject = getSubject(request, response);
        // If the subject isn't identified, redirect to login URL
        if (subject.getPrincipal() == null) {
            saveRequestAndRedirectToLogin(request, response);
        } else {
            //一.拿到请求头
            HttpServletRequest req = (HttpServletRequest)request;
            // 拿到响应头
            HttpServletResponse resp = (HttpServletResponse)response;
            //设置响应头
            resp.setContentType("application/json;charset=UTF-8");
            String xr = req.getHeader("X-Requested-With");
            //二.判断这个请求头是否是Ajax请求
            if(xr!=null && "XMLHttpRequest".equals(xr)){
                //返回一个json {"success":false,"msg":"权限不足,请充值!"}
                resp.getWriter().print("{\"success\":false,\"msg\":\"对不起,您的权限不足!\"}");
            }else {
                //普通请求:拿到没有权限的跳转路径,进行跳转
                String unauthorizedUrl = getUnauthorizedUrl();
                if (StringUtils.hasText(unauthorizedUrl)) {
                    WebUtils.issueRedirect(request, response, unauthorizedUrl);
                } else {
                    WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
                }
            }
        }
        return false;
    }
}

修改applicationContext-shiro.xml

key=“aisellPerms” :确定权限过滤器的名称

    <!--  这个的shiro过滤器->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		...
        <!-- 设置权限过滤器 -->
        <property name="filters">
            <map>
                <entry key="aisellPerms" value-ref="aisellPermissionsAuthorizationFilter"/>
            </map>
        </property>
    </bean>

    <!-- 配置自定义shiro过滤器 -->
    <bean id="aisellPermissionsAuthorizationFilter" class="com.xpc.web.shior.AisellPermissionsAuthorizationFilter" />

菜单配置

Menu用模板快速生成Menu,同时自己配好表与表之间的关系

    //@JsonIgnore    让它不再生成JSON
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    @JsonIgnore
    private Menu parent;

    // 临时属性 -> 这个字段JPA就不管它了
    @Transient
    private List<Menu> children = new ArrayList<>();

Permission

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="menu_id")
    private Menu menu;

MenuRepository

    @Query("select distinct m from Employee e join e.role r join r.permission p join p.menu m where e.id = ?1")
    List<Menu> findByUser(Long userId);

MenuServiceImpl

package com.xpc.service.impl;

import com.xpc.common.UserContext;
import com.xpc.domain.Employee;
import com.xpc.domain.Menu;
import com.xpc.repository.MenuRepository;
import com.xpc.service.IMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
public class MenuServiceImpl extends BaseServiceImpl<Menu,Long> implements IMenuService {

    @Autowired
    private MenuRepository menuRepository;

    @Override
    public List<Menu> findLoginMenu() {
        //1.准备一个装父菜单的容器
        List<Menu> parentMenus = new ArrayList<>();
        //2.拿到当前登录用户的所有子菜单
        Employee loginUser = UserContext.getUser();
        List<Menu> children = menuRepository.findByUser(loginUser.getId());
        //3.遍历子菜单,设置它们的关系
        for (Menu child : children) {
            //3.1 根据子菜单拿到它对应的父菜单
            Menu parent = child.getParent();
            //3.2 判断这个父菜单是否在容器中
            if(!parentMenus.contains(parent)){
                //3.3 如果不在,把父菜单放进去
                parentMenus.add(parent);
            }
            //3.4 为这个父菜单添加对应的子菜单
            parent.getChildren().add(child);
        }
        return parentMenus;
    }
}

UtilController
以Json格式返回前台

    //chai菜单管理
    @RequestMapping("/loginUserMenu")
    @ResponseBody
    public List<Menu> loginUserMenu(){
        return menuService.findLoginMenu();
    }

修改main.jsp中的路径

 url:'/util/loginUserMenu',

shiro:hasPermission
没有权限,页面就不显示这个按钮

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
...
<%-- employee:delete 这个要和数据库对应上 --%>
<shiro:hasPermission name="employee:delete">
    <a href="javascript:;" data-method="delete" class="easyui-linkbutton" iconCls="icon-remove" plain="true">删除</a>
</shiro:hasPermission>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值