基础准备:
1.一些基础依赖,lombok,security
2.基础的controller,mapper,pojo,service建好
3.先实现自定义用户登录
![](https://img-blog.csdnimg.cn/15cd4f12e7244ae6bf60ff008782af7c.png)
![](https://img-blog.csdnimg.cn/4849dfa21d0d49a08abdf94c428993cf.png)
4.完成基础自定义用户登录之后,开始给用户设置权限了。
4.1 User.java要实现UserDetails,并重写里面的方法
4.2 UserServiceImpl.java这里进行一些修改
运行一下程序,打印一下登录用户拥有什么角色,效果:
5.接下来是进行过滤器的编写了。
@Component
public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
//用来路径匹配的一个工具类
AntPathMatcher pathMatcher = new AntPathMatcher();
@Autowired
MenuService menuService;
//主要业务在这里写
@Override
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
//获取当前的请求路径
String requestUrl = ((FilterInvocation) o).getRequestUrl();
System.out.println("我请求的url是>>>"+requestUrl);
//查询所有的菜单
List<Menu> menus = menuService.getAllMenus();
System.out.println(menus);
//遍历菜单
for (Menu menu : menus) {
//与请求地址进行匹配
if (pathMatcher.match(menu.getPattern(),requestUrl)){
//此处为地址匹配上的业务
//1.从查询到的菜单集合中,拿到对应的角色
List<Role> roles = menu.getRoles();
//2.把结果return出去
String[] roleArr = new String[roles.size()];
for (int i = 0; i < roleArr.length; i++) {
roleArr[i] = roles.get(i).getName();
System.out.println(roleArr);
}
return SecurityConfig.createList(roleArr);
}
}
//这是地址匹配不上的,那么就给一个ROLE_login作为标识符
return SecurityConfig.createList("ROLE_login");
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return false;
}
}
再看看控制台,看看对应的角色是不是也设置上去了
以上完成了根据url分析出该url需要的角色
下一步就是判断当前登录用户有没有对应的角色
@Component
//该类是根据过滤器执行完返回的configAttributes,判断是否登录成功
public class MyAccessDecisionManager implements AccessDecisionManager {
/**
*
* @param authentication 当前登录的用户
* @param object
* @param configAttributes 过滤器返回的值
* @throws AccessDeniedException
* @throws InsufficientAuthenticationException
*/
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
//1.过滤器返回的值,根据“ROLE_XXX“,判断是不是与请求地址匹配
//匹配不上就给用户加上”ROLE_login“
for (ConfigAttribute attribute : configAttributes) {
//如果是ROLE_login,说明没有匹配上地址
if ("ROLE_login".equals(attribute.getAttribute())){
if (authentication instanceof AnonymousAuthenticationToken){
//没有登录
throw new AccessDeniedException("请登录");
}
else {
//登录了
return;
}
}
//地址匹配上
//1.当前用户拥有的角色
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority authority : authorities) {
//如果当前用户拥有的角色 跟 请求地址所需要的角色匹配上的话
if (authority.getAuthority().equals(attribute.getAttribute())){
System.out.println("我具备的角色>>>"+authority.getAuthority()+" 和 所需要的角色"+attribute.getAttribute()+" 匹配上咯");
return;
}
}
//以上两个情况都没有,抛出一个异常
throw new AccessDeniedException("非法请求");
}
}
@Override
public boolean supports(ConfigAttribute attribute) {
return false;
}
@Override
public boolean supports(Class<?> clazz) {
return false;
}
}
以上两个类都要交给Spring管理,然后在SecurityConfig中注入
测试结果:
在地址栏输入”localhost:9009/admin/hello“
首先是要你登录
但是在此之前,MyFilterInvocationSecurityMetadataSource.java会发生作用,根据我们输入的url判断出该url需要哪些角色,我在控制栏中打印了一下:
说明 /admin/hello 这个url是需要角色为admin的用户才能访问
此时MyFilterInvocationSecurityMetadataSource.java这个类的返回值就是url所需的角色
下一步,用户登录成功后,同时会查询该用户拥有哪些角色
我登录的是root用户,拥有dba和admin的角色
到此,该用户是可以访问localhost:9009/admin/hello这个地址的
用角色为user的用户登录,看看访问能不能访问admin/hello