1.先根据用户查询出菜单
2根据用户发送过来的URL资源请求判断那些角色可以访问
3.根据当前用户登陆的角色和数据库里角色做个比对
例如
1.查询资源表id 7
的路径,对应的中间表7
- 6
,查询到的是角色表的id 7
系统管理员
2.根据用户表id 3
管理员名字,对应的中间表是rid 6
,查询出角色表id 6
系统管理员
此优点:是没有在代码中写死,如果想改,可以到数据库修改权限
资源表
资源表和角色表
角色表
用户表
用户角色中间表
实体类中包含菜单和角色集合
/**
* 菜单实体类
*/
public class Menu {
private Integer id; //id
private String url;//路径
private String path;
private String component; //组件的名
private String name; //菜单名
private String iconcls; //图片
private Boolean keepalive;
private Boolean requireauth;
private Integer parentid;
private Boolean enabled; //是否启动
private List<Menu> children; //菜单
private List<Role> roles; //角色
获取登陆用户ID,返回用户菜单
/**
*
* @return 获取登陆用户ID,返回用户菜单
*/
public List<Menu> getMenusByHrId() {
return menuMapper.getMenusByHrId(((Hr) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId());
}
查询出用户
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
Hr hr = hrMapper.loadUserByUsername(s);
if (hr == null){
throw new UsernameNotFoundException("用户不存在");
}
hr.setRoles(roleMapper.getRolesByHrId(hr.getId()));//根据用户获取角色id
return hr;
}
2.使用拦截器过滤当前请求中的角色
@Component
public class MyFilter implements FilterInvocationSecurityMetadataSource {
@Autowired
MenuService menuService; //查询出菜单
AntPathMatcher antPathMatcher = new AntPathMatcher(); //路径匹配
/**
*
* @param o 发来的请求中提取当前请求地址
* @return 返回当前请求需要的角色
* @throws IllegalArgumentException
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
String requestUrl = ((FilterInvocation) o).getRequestUrl(); //调用过滤器拦截当前请求地址
List<Menu> list = menuService.getAllMenus(); //数据库查询出菜单
for (Menu menu :list){
if (antPathMatcher.match(menu.getUrl(),requestUrl)){ //匹配数据库URL地址
List<Role> roles = menu.getRoles(); //get角色访问
String[] strArr = new String[roles.size()];
for (int i = 0;i<roles.size();i++){
strArr[i] = roles.get(i).getName();
}
return SecurityConfig.createList(strArr);//返回角色
}
}
return SecurityConfig.createList("ROLB_LOGIN");//没有角色就做个标记
}
3.当前用户是否具备有这样的角色
/**
* 当前用户是否具备角色
*/
@Component
public class MyAccessDesicision implements AccessDecisionManager {
/**
*
* @param authentication 当前用户的角色回调
* @param o 获取请求地址
* @param collection 返回值角色
* @throws AccessDeniedException
* @throws InsufficientAuthenticationException
*/
@Override
public void decide(Authentication authentication, Object o,
Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
//当前用户具有的角色
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (ConfigAttribute configAttribute : collection){
if (configAttribute.getAttribute().equals("ROLB_LOGIN")){
//ROLB_LOGIN 判断当前用户是否具备角色登陆
if (authentication instanceof UsernamePasswordAuthenticationToken){
return;
}else{
throw new AccessDeniedException("权限不足,请求联系管理员"); //没登陆
}
}
for (GrantedAuthority authority:authorities){
if (authority.getAuthority().equals(configAttribute.getAttribute())){
return; //角色相等
}
}
throw new AccessDeniedException("权限不足,请求联系管理员");
}
}