首先创建4个类
流程大致如下:
1、容器启动 加载系统资源与权限列表(HashMap) MyInvocationSecurityMetadataSourceService中的loadResourceDefine
@Service public class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource { @Autowired private PermissionDao permissionDao; private HashMap<String, Collection<ConfigAttribute>> map =null; /** * 加载所有资源与权限的关系 */ public void loadResourceDefine(){ map = new HashMap<>(); Collection<ConfigAttribute> array; ConfigAttribute cfg; List<Permission> permissions = permissionDao.findAll(); for(Permission permission : permissions) { array = new ArrayList<>(); //角色名称 cfg = new SecurityConfig(permission.getName()); array.add(cfg); map.put(permission.getUrl(), array); } } /** *返回请求资源所需要的权限 */ @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { if(map ==null) loadResourceDefine(); HttpServletRequest request = ((FilterInvocation) object).getHttpRequest(); AntPathRequestMatcher matcher; String resUrl; for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) { resUrl = iter.next(); matcher = new AntPathRequestMatcher(resUrl); if(matcher.matches(request)) { return map.get(resUrl); } } return null; } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } @Override public boolean supports(Class<?> clazz) { return true; } }
2、用户发出请求
3、过滤器拦截 MyFilterSecurityInterceptor中的doFilter()
@Service public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { /** * 过滤请求 调用FilterInvocationSecurityMetadataSource 资源和 MyAccessDecisionManager进行验证 */ @Autowired private FilterInvocationSecurityMetadataSource securityMetadataSource; @Autowired public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) { super.setAccessDecisionManager(myAccessDecisionManager); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { /** * FilterInvocation 把doFilter传进来的request、response、chain对象保存起来 */ FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public void invoke(FilterInvocation fi) throws IOException, ServletException { //fi里面有一个被拦截的url //里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限 HashMap中 //再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够 //object为FilterInvocation对象 // //1、获取请求资源的权限 //执行Collection<ConfigAttribute> attributes=securityMetadataSource.getAttributes(fi); //2、是否拥有权限 //执行 this.accessDecisionManager.decide(authenticated,fi,attributes); InterceptorStatusToken token = super.beforeInvocation(fi); /** * InterceptorStatusToken token = super.beforeInvocation(fi);会调用MyAccessDecisionManager中decide方法 * 和MyInvocationSecurityMetadataSource中getAttributes方法 */ try { //执行下一个拦截器 fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.afterInvocation(token, null); } } @Override public void destroy() { } @Override public Class<?> getSecureObjectClass() { return FilterInvocation.class; } @Override public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } }
4、取得请求资源所需权限MyInvocationSecurityMetadataSourceService中getAttributes()
5、匹配用户的权限和请求所需要的权限MyAccessDecisionManager中decide()
@Service 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 { //如果访问资源不需要任何权限则直接通过 if(null== configAttributes || configAttributes.size() <=0) { return; } ConfigAttribute c; String needRole; //遍历configAttributes看用户是否有访问资源的权限 for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) { c = iter.next(); needRole = c.getAttribute(); for(GrantedAuthority ga : authentication.getAuthorities()) { //ga 用户所被赋予的权限,needRole 访问相应资源应具有的权限 if(needRole.trim().equals(ga.getAuthority())) { return; } } } // 如果访问被拒绝,实现将抛出一个AccessDeniedException异常。 throw new AccessDeniedException("no right"); } @Override public boolean supports(ConfigAttribute attribute) { return true; } @Override public boolean supports(Class<?> clazz) { return true; } }
6、登录
@Service public class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口 @Autowired UserDao userDao; @Autowired PermissionDao permissionDao; /** *点击登录跳转 保存用户权限 * */ public UserDetails loadUserByUsername(String username) { SysUser user = userDao.findByUserName(username); if (user != null) { List<Permission> permissions = permissionDao.findByAdminUserId(user.getId()); List<GrantedAuthority> grantedAuthorities = new ArrayList <>(); for (Permission permission : permissions) { if (permission != null && permission.getName()!=null) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName()); grantedAuthorities.add(grantedAuthority); } } return new User(user.getUsername(), user.getPassword(), grantedAuthorities); } else { throw new UsernameNotFoundException("admin: " + username + " do not exist!"); } } }
7、验证并授权