Spring Security-动态权限控制(2)

6创建service层

MenuService.java

 
package com.service;
 ​
 import com.entity.Menu;
 import com.mapper.MenuMapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 ​
 import java.util.List;
 ​
 @Service
 public class MenuService {
 ​
     @Autowired
     MenuMapper menuMapper;
 ​
    public  List getAllMenus(){
         return menuMapper.getAllMenus();
     }
 ​
 ​
 }

MyUserDetailsService.java

 package com.service;
 ​
 import com.entity.User;
 import com.mapper.UserMapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.stereotype.Service;
 ​
 ​
 @Service("userDetailsService")
 public class MyUserDetailsService implements UserDetailsService {
 ​
     @Autowired
     private UserMapper userMapper;
 ​
 ​
 ​
     @Override
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
 ​
         //根据用户名 查询 --调用mapper进行查询----- User 是咱 自己的entity,
         //因为他class User implements      UserDetails  ,这里不要引错
        User info = userMapper.loadUserByUsername(username);  
         //判断
         if(info==null){   //没有用户 验证失败
             throw new UsernameNotFoundException("用户名不存在");
         }
         //设置密码--注意加密
         info.setPassword(new BCryptPasswordEncoder().encode(info.getPassword()));
         //根据当前用户id 查询 当前 用户的角色
         info.setRoles(userMapper.getUserRolesById(info.getId()));
         //返回User
         return info;
     }
 }
 ​

7创建 controller层java

TestController.java

新增,导出 修改,删除 查询的 url 已经再数据库 menu中进行配置

Spring Security-动态权限控制(2)_第1张图片

 
package com.controller;
 ​
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
 ​
 ​
 @Controller
 @RequestMapping("/test")
 public class TestController {
 ​
     @GetMapping("/add")  //新增
     @ResponseBody
     public String add(){ return "hello add"; }
     @GetMapping("/export") //导出
     @ResponseBody
     public String export(){
         return "hello export";
     }
 ​
     @GetMapping("/update") //修改
     @ResponseBody
     public String update(){
         return "hello update";
     }
 ​
     @GetMapping("/delete") //删除
     @ResponseBody
     public String delete(){
         return "hello delete";
     }
 ​
     @GetMapping("/query")  //查询
     @ResponseBody
     public String query(){
         return "hello query";
     }
     
     //自定义登录页面的url
     @GetMapping("/toLogin")
     public String login(){
         return "login";
     }
     //认证成功过后 进入主页
     @GetMapping("/success")
     public String success(){
         return "main";
     }
 }

8创建MyAccessDecisionManager 访问决策管理器

AccessDecisionManager是一个接口,声明了三个方法,核心方法是decide用以授权,另外两个supports方法主要起辅助作用,大都执行检查操作的。

 
package com.config;
 ​
 import org.springframework.security.access.AccessDecisionManager;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.access.ConfigAttribute;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.authentication.InsufficientAuthenticationException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.stereotype.Component;
 ​
 import java.util.Collection;
 ​
 @Component
 public class MyAccessDecisionManager implements AccessDecisionManager {
     @Override
     public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
 ​
         for(ConfigAttribute attribute:configAttributes){
            
             if("ROLE_login".equals(attribute.getAttribute())){
                 //路径不在数据库配置范围
                 if(authentication instanceof AnonymousAuthenticationToken){ // 用户未登录
 ​
                  
                     throw new AccessDeniedException("非法请求尚未登录 ,请先登录");
                 }else{
                     return ; // 用户已经登录, 无需判断, 方法到此结束
                 }
 ​
             }
             // 获取当前登录用户的角色
             Collection authorities = authentication.getAuthorities();
           
             for(GrantedAuthority authority:authorities){
                 if(authority.getAuthority().equals(attribute.getAttribute())){
 ​
                     return;   // 当前用户具备所需的角色, 无需判断
                 }
             }
 ​
         }
 ​
         throw new AccessDeniedException("非法请求,权限不足,请联系管理员");
 ​
     }
 ​
     @Override
     public boolean supports(ConfigAttribute attribute) {
         return true;
     }
 ​
     @Override
     public boolean supports(Class clazz) {
         return true;
     }
 }

9 创建过滤器

 package com.filter;
 ​
 import com.entity.Menu;
 import com.entity.Role;
 import com.service.MenuService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.ConfigAttribute;
 import org.springframework.security.access.SecurityConfig;
 import org.springframework.security.web.FilterInvocation;
 import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
 import org.springframework.stereotype.Component;
 import org.springframework.util.AntPathMatcher;
 ​
 import java.util.Collection;
 import java.util.List;
 ​
 @Component
 public class MyFilter implements FilterInvocationSecurityMetadataSource {
     @Autowired
     public MenuService menuService;
 ​
     //路径匹配符  直接用于匹配路径
     AntPathMatcher pathMatcher=new AntPathMatcher();
 ​
 ​
     @Override
     public Collection getAttributes(Object object) throws IllegalArgumentException {
        String url = ((FilterInvocation)object).getRequestUrl();//获取请求地址
         List allMenus = menuService.getAllMenus();
 ​
         for(Menu menu:allMenus){
             if(pathMatcher.match(menu.getPattern(),url)){
                 List roles = menu.getRoles();
                 String[]rolesStr = new String[roles.size()];
                 for(int i=0;i getAllConfigAttributes() {
         return null;
     }
 ​
     @Override
     public boolean supports(Class clazz) {
         return true;
     }
 }

10创建配置类

 package com.config;
 ​
 ​
 import com.filter.MyFilter;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.config.annotation.ObjectPostProcessor;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
 import org.springframework.security.web.firewall.HttpFirewall;
 import org.springframework.security.web.firewall.StrictHttpFirewall;
 ​
 ​
 @Configuration    //配置类
 public class SecurityConfig  {
 ​
     @Autowired
     MyFilter myFilter;
 ​
     @Autowired
     MyAccessDecisionManager myAccessDecisionManager;
 ​
     
 ​
     @Bean
     PasswordEncoder passwordEncoder(){
         return new BCryptPasswordEncoder();
     }
 ​
 ​
     @Bean
     public HttpFirewall allowUrlEncodedslashHttpFirewall() {
         StrictHttpFirewall firewall = new StrictHttpFirewall();//此处可添加别的规则,目前只设置允许双
         firewall.setAllowUrlEncodedDoubleSlash(true);
         return firewall;
     }
 ​
 ​
     @Bean
     public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 ​
 ​
         //配置没有权限访问跳转的页面
         http.exceptionHandling().accessDeniedPage("/403.html");
         http.authorizeRequests()  //开始请求权限配置。
                 .withObjectPostProcessor(new ObjectPostProcessor() {
                     @Override
                     public  O postProcess(O object) {
                         object.setAccessDecisionManager(myAccessDecisionManager);
                         object.setSecurityMetadataSource(myFilter);
                         return object;
                     }
                 })
                 //.anyRequest().authenticated()
                 .and()
                 .formLogin()
                             .loginPage("/test/toLogin")   //登录页面显示
                             .loginProcessingUrl("/user/login")  //html form action
                             .defaultSuccessUrl("/test/success",true)
                 .permitAll()
 ​
 ​
                 .and()
                 .csrf().disable();
         return http.build();
     }
 ​
 ​
     @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
         return (web) -> web.ignoring().antMatchers("/images/**", "/js/**", "/css/**");
      }
 }

11创建页面

login.html

 

 
 
     
     登录页面
     
 
 
 ​
    
   
   
     
   

main.html

 

 
 
     
     Title
     
 
 
 

这是 主页

 
    您好  ​      
         

管理员

         增加1          修改1          删除1          导出1  ​          查询1      
 ​      
         

普通用户

 ​          导出  ​          查询      
 ​  ​  
 ​  ​    

12 启动类

 package com;
 ​
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 ​
 ​
 @SpringBootApplication
 @MapperScan(basePackages = "com.mapper")
 public class SS1222App {
     public static void main(String[] args) {
         SpringApplication.run(SS1222App.class,args);
     }
 }

13 启动测试

Spring Security-动态权限控制(2)_第2张图片

Spring Security-动态权限控制(2)_第3张图片 

我们发同一个 页面, 不同的 角色 ,权限不同, 因此会 看到不同的 页面显示 这就是 基于路径的权限控制

你可能感兴趣的:(Spring,Security,spring,java,后端)