FilterChainDefinitionMapBuilder:
public class FilterChainDefinitionMapBuilder {
@Autowired
private IPermissionService permissionService;
public Map createFilterChainDefinitionMap(){
…
filterChainDefinitionMap.put("/logout","logout"); //不登录也可以访问
//从数据库拿到数据,放到咱们的Map中
//1.拿到所有权限
List 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;
}
修改代码:
欢迎[ ]登录,退出
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;
}
}
@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();
}
//根据当前登录用户拿到对应的权限
@Query("select distinct p.sn from Employee e join e.roles r join r.permissions p where e.id = ?1")
Set findSnByEmp(Long employeeId);
IPermissionService
Set findSnByEmp(Long employeeId);
PermissionServiceImpl
@Override
public Set findSnByEmp(Long employeeId) {
return permissionRepository.findSnByEmp(employeeId);
}
public class JpaRealm extends AuthorizingRealm {
@Autowired
private IEmployeeService employeeService;
@Autowired
private IPermissionService permissionService;
//AuthorizationInfo:授权(是否有权限进入操作)
// 我们只需要把相应的权限交给Shiro,它就会自动比对
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//拿到主体信息(指的就是当前登录用户)
Employee loginUser = UserContext.getUser();
//获取权限资源(这里假设已经根据用户名到数据库中获取到了)
Set permissions = permissionService.findSnByEmp(loginUser.getId());
//permissions.add("employee:index");
//permissions.add("role:index");
//permissions.add("employee:*");
//拿到授权对象,并且所有权限交给它
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setStringPermissions(permissions);
//返回授权对象
return simpleAuthorizationInfo;
}
…
}
咱们所有的请求可以分为两大类,一个是跳转页面,xxx/index 还有一类是Ajax请求期望返回的是{“success”:false,”message”:”没有权限”}
区分处理是否是Ajax请求,普通跳转页面的请求 ,就跳转没有权限的页面,如果是ajax请求返回{“success”:false,”message”:”没有权限”}
?怎么Ajax 判断请求头里面是否有X-Requested-With
跳转页面请求头
Ajax请求多个一个请求头X-Requested-With XMLHttpRequest
区分处理–shiro默认的权限过滤器不支持,需要自定义过滤器才行
上面的配置会交给
自定义权限的功能:可以参考我们给大家准备Shiro的资料
//ItsourceYxbPermissionsAuthorizationFilter:自定义权限过滤器
public class ItsourceYxbPermissionsAuthorizationFilter 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 {
//登录成功后没有权限的操作
//1.转成http的请求与响应操作
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
//2.根据请求确定是什么请求
String xRequestedWith = httpRequest.getHeader("X-Requested-With");
if (xRequestedWith != null &&"XMLHttpRequest".equals(xRequestedWith)) {
//3.在这里就代表是ajax请求
//表示ajax请求 {"success":false,"message":"没有权限"}
httpResponse.setContentType("text/json; charset=UTF-8");
httpResponse.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
FilterChainDefinitionMapBuilder
public Map createFilterChainDefinitionMap(){
Map filterChainDefinitionMap = new LinkedHashMap();
//注:对于一些不登录也可以放行的设置(大家可以根据实际情况添加)
filterChainDefinitionMap.put("/login","anon");
filterChainDefinitionMap.put("*.js","anon");
filterChainDefinitionMap.put("*.css","anon");
filterChainDefinitionMap.put("/css/**","anon");
filterChainDefinitionMap.put("/js/**","anon");
filterChainDefinitionMap.put("/easyui/**","anon");
filterChainDefinitionMap.put("/images/**","anon");
filterChainDefinitionMap.put("/logout","logout"); //不登录也可以访问
//这个值之后从数据库中查询到【用户-角色-权限-资源】
//从数据库拿到数据,放到咱们的Map中
//1.拿到所有权限
List permissions = permissionService.findAll();
//2.遍历权限,拿到权限 资源
for (Permission permission : permissions) {
String url = permission.getUrl();//资源
String sn = permission.getSn();//权限
//把路径与资源放到拦截中去
filterChainDefinitionMap.put(url,"yxbPerms["+sn+"]");
}
filterChainDefinitionMap.put("/**","authc");
return filterChainDefinitionMap;
}
用户->角色->权限->菜单
@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
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="menu_id")
private Menu menu;
//根据用户名拿到一个人对应的所有子菜单
@Query("select distinct m from Employee e join e.roles r join r.permissions p join p.menu m where e.id = ?1")
List
@Override
public List
@RequestMapping("/loginUserMenus")
@ResponseBody
public List loginUserMenus(Long id){
Employee loginUser = UserContext.getUser();
return menuService.findByLoginUser(loginUser.getId());
}
添加
修改
删除