智能供銷系統_6

今日是進行動態菜單生成與權限管理的完善
# 一.session處理javascript

## 1.1 登陸成功後主體爲用戶
> 之前登陸成功,傳的是username,如今傳==主體Employee對象==
```
//身份認證java

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
   ...
    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(loginUser,password,salt,getName());
    return authenticationInfo;
}


```web

## 1.2 UserContext
> session是從subject獲取ajax

> 存在shiro的session中後,HttpSession也會有值```spring

public class UserContext {

    public static final String USER_IN_SESSION ="loginUser";

    //把登陸成功的用戶放到session中
    public static void setUser(Employee loginUser){
        Subject subject = SecurityUtils.getSubject();
        //表明登陸成功,把當前登陸用戶放到Session中去(shiro的session)
        //1.拿到session
        Session session = subject.getSession();
        //2.把當前登陸成功的用戶放到session中去
        session.setAttribute(USER_IN_SESSION, loginUser);

    }
    
    //獲取到當前登陸用戶
    public static Employee getUser(){
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        Employee employee = (Employee) session.getAttribute(USER_IN_SESSION);
        return employee;
    }

}


```數據庫

# 二.受權管理apache

## 2.1 FilterChainDefinitionMapFactory
> 保存全部權限過濾的數據都是從數據庫中獲取```json

@Autowired
private IPermissionService permissionService;
public Map<String,String> createFilterChainDefinitionMap(){
    ...
    //拿到全部權限
    List<Permission> perms = permissionService.findAll();
    //設置相應的權限
    perms.forEach(p -> {
        filterChainDefinitionMap.put(p.getUrl(), "perms["+p.getSn()+"]");
    });

    filterChainDefinitionMap.put("/**", "authc");

    return filterChainDefinitionMap;
}


```session

## 2.2 獲取受權
> 受權部分的數據也是從數據庫中得到的
>> 應該拿到當前登陸用戶的全部權限app

### PermissionRepository
> JPQL關聯原則: 1.不寫on  2.關聯對象的別名.屬性
```

//根據用戶拿到他對應的全部權限
@Query("select distinct p.sn from Employee e join e.roles r join r.permissions p where e.id = ?1")
Set<String> findPermsByUser(Long userId);


```
### PermissionService(調用略...)
### JpaRealm
> 拿到當前登陸用戶,再獲取它的權限
```

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    Employee loginUser = UserContext.getUser();
   //根據當前用戶拿到對應的權限
    Set<String> perms = permissionService.findPermsByUser(loginUser.getId());
    //準備並返回AuthorizationInfo這個對象
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    authorizationInfo.setStringPermissions(perms);
    return authorizationInfo;
}


```

## 2.3 Ajax請求的權限處理
> shiro處理沒有權限是跳轉頁面,而咱們若是是ajax請求,咱們但願是返回json數據
> ajax請求會有一個請求頭:X-Requested-With: XMLHttpRequest
> 須要自定義一個shiro的權限過濾器

### 2.3.1 自定義權限過濾器```

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;
    }
}

爲保留原有的功能,幾乎全部代碼都是拷的父類,只在必要的地方作修改
```

### 2.3.2 applicationContext-shiro.xml
> 配置權限過濾器
>> entry key="aisellPerms":肯定權限過濾器的名稱---與權限的前綴一致key[權限]
    <!--  真正實現權限的過濾器 它的id名稱和web.xml中的過濾器名稱同樣 -->
 

<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="cn.itsource.aisell.shiro.AisellPermissionsAuthorizationFilter" />


```

### 2.3.3 修改過濾器配置
```

@Autowired
private IPermissionService permissionService;
public Map<String,String> createFilterChainDefinitionMap(){
    ...
    //拿到全部權限
    List<Permission> perms = permissionService.findAll();
    //設置相應的權限
    perms.forEach(p -> {
        filterChainDefinitionMap.put(p.getUrl(), "aisellPerms["+p.getSn()+"]");
    });
    ...
}


 

# 三.菜單管理

> 員工 -> 角色 -> 權限 -> ==菜單==## 3.1 Menu
> 菜單domain的自關連配置
>> 須要配置雙向,可是不能讓JPA去管理一對多(咱們本身管理:@Transient)
>>> 雙向生成JSON會產生死循環,須要一邊進行忽略:@JsonIgnore
```

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

    // 臨時屬性 -> 這個字段JPA就無論它了
    @Transient
    private List<Menu> children = new ArrayList<>();


```

注 : 要保證menu正確顯示

//在menu類中應該配有getText,一保證得到對應的文本信息
public String getText() {
        return name;
    }

## 3.2 MenuRepository
```

public interface MenuRepository extends BaseRepository<Menu,Long>{
    @Query("select distinct m from Employee e join e.roles r join r.permissions p join p.menu m where e.id = ?1")
    List<Menu> findByUser(Long userId);
}


```

## 3.2 MenuService
> 根據設計只能經過員工找到子菜單
>> 須要經過子菜單拿到父菜單
>>> 判斷這個父菜單是否已經存到集合中
>>>> 若是這個菜單單沒有存起來,放到集合中
> 把當前這個子菜單放到父菜單中去

```

@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;
}


## 3.3 UtilController中返回值

@Autowired
private IMenuService menuService;

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

 

## 3.4 main.jsp修改路徑
 

$('#menuTree').tree({
            url:'/util/loginUserMenu',
            ...

 


# shiro:hasPermission
> 沒有這個權限,就不展現對應的按鍵
```

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
...
<shiro:hasPermission name="employee:delete">
    <a href="javascript:;" data-method="delete" class="easyui-linkbutton" iconCls="icon-remove" plain="true">刪除</a>
</shiro:hasPermission>

```

相關文章
相關標籤/搜索