获取到所有权限进行判断
public class FilterChainDefinitionMapBuilder {
@Autowired
private IPermissionService permissionService;
public Map<String,String> createFilterChainDefinitionMap(){
…
filterChainDefinitionMap.put("/logout","logout"); //不登录也可以访问
//从数据库拿到数据,放到咱们的Map中
//1.拿到所有权限
List<Permission> permissions = permissionService.findAll();
//2.遍历权限,拿到权限与资源
for (Permission permission : permissions) {
String url = permission.getUrl();//资源
String sn = permission.getSn();//权限
//把路径与资源放到拦截中去
filterChainDefinitionMap.put(url,"perms["+sn+"]");
}
filterChainDefinitionMap.put("/**","authc");
return filterChainDefinitionMap;
}
}
拿到登录用户
//完成登录的认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
String username = token.getUsername();
Employee loginUser = employeeService.findByUsername(username);
if(loginUser==null){
return null;
}
//拿到登录用户的密码
String dbPassword = loginUser.getPassword();
//设置加盐
ByteSource salt = ByteSource.Util.bytes("itsource");
SimpleAuthenticationInfo authorizationInfo = new SimpleAuthenticationInfo(loginUser,dbPassword,salt,getName());
return authorizationInfo;
}
新建一个UserContext 类
public class UserContext {
private static final String USER_IN_SESSION = "loginUser";
/**
* 把当前登录用户放入Session
* @param loginUser
*/
public static void setUser(Employee loginUser) {
Subject subject = SecurityUtils.getSubject();
subject.getSession().setAttribute(USER_IN_SESSION, loginUser);
}
/**
* 从Session中获取User
*/
public static Employee getUser() {
Subject subject = SecurityUtils.getSubject();
Employee curentUser = (Employee) subject.getSession().getAttribute(USER_IN_SESSION);
return curentUser;
}
}
.LoginController:登录成功后把用户放到Session中
@RequestMapping(value="/login",method = RequestMethod.POST)
@ResponseBody
public JsonResult login(String username, String password){
//1.拿到访问的主体(当前登录用户)
Subject subject = SecurityUtils.getSubject();
//2.判断这个用户是否已经登录(通过验证)
if(!subject.isAuthenticated()){
….
}
//登录成功后,把当前登录用户放到session中
//1.拿到当前登录用户(这个主体就是当前登录用户)
Employee loginUser = (Employee) subject.getPrincipal();
//2.当前登录用户放到session中
UserContext.setUser(loginUser);
return new JsonResult();
}
根据用户id拿到权限
在PermissionRepository 添加一个方法
//根据当前登录用户拿到对应的权限
@Query("select distinct p.sn from Employee e join e.roles r join r.permissions 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);
}
JpaRealm:进入权限判断
@Override
//授权验证 AuthorizationInfo:授权(是否有权限进入操作)
// 我们只需要把相应的权限交给Shiro,它就会自动比对
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//当前用户的权限弄出来 --给shiro 让shiro 进行比较 做权限的操作
//得到主体/用户
Employee employee =(Employee)principalCollection.getPrimaryPrincipal();
//根据用户 从数据库去拿到对应权限 加入到shiro里面
Set<String> permissions = permissionService.findPermissionsByLoginUser(employee.getId());
//查询数据库 jpql语句
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addStringPermissions(permissions);
//返回到shiro里面 就会进行权限的判断
return simpleAuthorizationInfo;
}
权限判断
一般请求和AJAX请求区分
Ajax请求多个一个请求头X-Requested-With XMLHttpRequest
自定义过滤器
package cn.itsource.aisell.shiro;
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 AisellPermissionAuthorizationFilter extends PermissionsAuthorizationFilter {
//怎么写
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
Subject subject = this.getSubject(request, response);
if (subject.getPrincipal() == null) {
this.saveRequestAndRedirectToLogin(request, response);
} else {
//如果拦截请求是ajax请求,返回json来处理 否者就返回页面
//X-Requested-With
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse)response;
//获取请求头
String header = req.getHeader("X-Requested-With");
if("XMLHttpRequest".equals(header)){
//返回json {"success":false,"msg":"没有权限"}
resp.setContentType("text/json;charset=UTF-8");
resp.getWriter().print("{\"success\":false,\"msg\":\"没有权限\"}");
}else {
//返回页面
String unauthorizedUrl = this.getUnauthorizedUrl();
if (StringUtils.hasText(unauthorizedUrl)) {
WebUtils.issueRedirect(request, response, unauthorizedUrl);
} else {
WebUtils.toHttp(response).sendError(401);
}
}
}
return false;
}
}
applicationContext-shiro.xml
...
<!--配置自定义权限过滤器-->
<property name="filters" >
<map>
<entry key="aisellPerm" value-ref="aisellPermissionAuthorizationFilter"></entry>
</map>
</property>
</bean>
<bean id="aisellPermissionAuthorizationFilter" class="cn.itsource.aisell.shiro.AisellPermissionAuthorizationFilter"></bean>
FilterChainDefinitionMapBuilder
@Autowired
private IPermissionService permissionService;
//得到Map
public Map buildFilterChaiDefinitionMap(){
/*按照 顺序放行 不能下载配置文件中,因为写死了,现在要动态获取后台数据库的
/s/login.jsp=anon
/login=anon
/s/permission.jsp = perms[user:*]
/**=authc
*/
Map map = new LinkedHashMap();
map.put("/login","anon");
map.put("*.js","anon");
map.put("*.css","anon");
map.put("/css/**","anon");
map.put("/js/**","anon");
map.put("/easyui/**","anon");
map.put("/images/**","anon");
map.put("/s/login.jsp","anon");
map.put("/s/permission.jsp","perms[user:*]");
//1.拿到所有权限
List<Permission> permissions = permissionService.findAll();
//遍历所有 拿到权限和资源
for (Permission permission : permissions) {
//放到map里面
String url = permission.getUrl();
String sn = permission.getSn();
map.put(url, "aisellPerm["+sn+":*]");
}
map.put("/**","authc");
return map;
}
菜单读取
Menu菜单
@Entity
@Table(name="menu")
public class Menu extends BaseDomain {
private String name;//菜单名称
private String url; //路径
private String icon; //图标
/**
* JsonIgnore:生成JSON的时候忽略这个属性
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="parent_id")
@JsonIgnore //这里生成json的时候要忽略,否则会造成功能相互调用
private Menu parent;
/**
* 还要配置一个一对多
* 这个字段不要交给JPA管理【到时候自己写代码管理】
* 数据库的menu表中就应该有一个children,而且还是List类型
* Transient:临时属性(JPA不管这个属性,和数据库没有关系)
*/
@Transient
private List<Menu> children = new ArrayList<>();
…
public String getText(){ //EasyUI的树需要一个text属性
return name;
}
}
Permission 添加一个
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="menu_id")
private Menu menu;
.MenuService
@Override
public List<Menu> findByLoginUser(Long userId) {
//准备父菜单容器
List<Menu> parentMenus = new ArrayList<>();
//从数据库中拿到子菜单
List<Menu> childrenMenus = menuRepository.findByLoginUser(userId);
//遍历子菜单(如果有父菜单放进入,没有单独创建)
for (Menu childrenMenu : childrenMenus) {
//拿到子菜单对应的父菜单
Menu parent = childrenMenu.getParent();
//判断如果父菜单中是否有这个菜单
if(parentMenus.contains(parent)){
//有的话,咱们就把子菜单放到父菜单中去
int i = parentMenus.indexOf(parent);
Menu parentMenu = parentMenus.get(i);
parentMenu.getChildren().add(childrenMenu);
}else{
//如果没有,再单独把父菜单放进去
parentMenus.add(parent);
parent.getChildren().add(childrenMenu);
}
}
return parentMenus;
}
UtilController
@RequestMapping("/loginUserMenus")
@ResponseBody
public List loginUserMenus(Long id){
Employee loginUser = UserContext.getUser();
return menuService.findByLoginUser(loginUser.getId());
}