一.编写相关页面
在本项目中,我们使用Spring Security 进行认证和授权,首先我们先编写相关页面。
1.编写登录页面admin_ login.html
2.编写登录失败页面admin_ fail.html
3.编写权限不足页面no_ permission.html
略过。知道其功能即可。
二.编写配置类
1.引入 Spring Security 相关依赖
        <!-- spring-security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- thymeleaf整合spring-security -->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>2.编写 Spring Security 配置类
// Security配置类
@Configuration
//下面这个注解是允许使用注解的方式使用鉴权配置
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // Spring Security配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 自定义表单登录
        http.formLogin()
                .loginPage("/backstage/admin_login") // 自定义登录页面
                .usernameParameter("username") // 用户名项
                .passwordParameter("password") // 密码项
                .loginProcessingUrl("/backstage/admin/login") // 表单提交路径
                .successForwardUrl("/backstage/index") // 登录成功页面
                .failureForwardUrl("/backstage/admin_fail"); // 登录失败页面
        // 权限拦截配置
        http.authorizeRequests()
                .antMatchers("/backstage/admin/login").permitAll() // 登录不需要认证
                .antMatchers("/backstage/admin_fail").permitAll()// 登录失败不需要认证
                .antMatchers("/backstage/admin_login").permitAll()// 登录页不需要认证
                .antMatchers("/**/*.css","/**/*.js").permitAll() // 放行静态资源
                .antMatchers("/backstage/**").authenticated();// 其余都需要认证
        // 退出登录配置
        http.logout()
                .logoutUrl("/backstage/admin/logout") // 退出登录路径
                .logoutSuccessUrl("/backstage/admin_login") // 退出登录成功后跳转的页面
                .clearAuthentication(true) // 退出成功后清除认证信息
                .invalidateHttpSession(true); // 退出成功后清除session
        // 异常处理
        http.exceptionHandling()
                .accessDeniedHandler(new MyAccessDeniedHandler()); //权限不足处理器
        // 关闭csrf防护
        http.csrf().disable();
        // 开启跨域访问
        http.cors();
    }
    // 密码加密器(在数据库中密文存储)
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}自定义权限不足处理器:
// 自定义权限不足处理器
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.sendRedirect("/backstage/no_permission"); // 重定向到权限不足页面
    }
}三.编写认证逻辑
登陆时的认证逻辑需要我们自己编写,需要写一个类继承UserDetailsService接口,然后实现loadUserByUsername函数来自定义认证逻辑。
先在AdminService.java中添加一个根据名字查询管理员的方法(为编写认证逻辑做准备)
    // 根据名字查询管理员
    public Admin findByAdminName(String username){
        QueryWrapper<Admin> wrapper = new QueryWrapper();
        //如果参数值和数据库的username字段的值相同的话就查询出来
        wrapper.eq("username",username);
        Admin admin = adminMapper.selectOne(wrapper);
        return admin;
    }然后再在AdminMapper.java中编写一个根据用户名查询权限的接口(为编写授权逻辑做准备)
    //根据用户名查询权限
    List<Permission> findAllPermission(String username);然后我们在 AdminMapper.xml中实现这个接口
这个功能也需要进行一个五表查询
    <select id="findAllPermission" parameterType="string" resultType="com.first.travel.pojo.Permission">
        select DISTINCT permission.* FROM
            admin
                LEFT JOIN admin_role
                          on admin.aid = admin_role.aid
                LEFT JOIN role
                          on admin_role.rid = role.rid
                LEFT JOIN role_permission
                          on role.rid = role_permission.rid
                LEFT JOIN permission
                          on role_permission.pid = permission.pid
        where admin.username = #{username}
        and permission.pid is not null
    </select>然后咱们在AdminService.java中调用此接口实现业务逻辑功能
    // 根据名字查询权限
    public List<Permission> findAllPermission(String username){
        return adminMapper.findAllPermission(username);
    }注意一点就是Spring Securit是让我们用post方式提交数据,所以要注意前端页面的提交方式不要写成get。
// 自定义认证授权逻辑
@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    private AdminService adminService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 1.认证
        Admin admin = adminService.findByAdminName(username);
        if (admin == null){
            throw new UsernameNotFoundException("用户不存在");
        }
        if(!admin.isStatus()){
            throw new UsernameNotFoundException("用户不可用");
        }
        // 2.授权
        List<Permission> permissions = adminService.findAllPermission(username);
        //GrantedAuthority是Spring Security要求的权限类型,所以我们需要把权限转成这种类型
        List<GrantedAuthority> grantedAuthorities = new ArrayList();
        for (Permission permission : permissions) {
            grantedAuthorities.add(new SimpleGrantedAuthority(permission.getPermissionDesc()));
        }
        // 3.封装为UserDetails对象
        UserDetails userDetails = User.withUsername(admin.getUsername())
                .password(admin.getPassword())
                .authorities(grantedAuthorities)
                .build();
        return userDetails;
    }
}四.后端鉴权配置
通过上面的操作我们已经对登录之后的用户进行了授权,即用户登录之后有哪些权限已经给到用户手里面了,接下来我们来看看鉴权配置,就是当用户拥有哪些权限的时候才能访问哪些资源,即用户拥有权限才能访问接口。
配置方式有两种:一种是在Spring Security.java中配置,另一种是用注解的方式
我们就是用注解的方式来配置一下(要在Spring Security中添加一句开启此功能的注解)
@EnableGlobalMethodSecurity(prePostEnabled = true)然后我们在个角色对应的控制类里添加注解配置鉴权即可
举个例子:
首先看看数据库里的权限都有哪些(注解中要填红框里那些)

比如我们在AdminController.java中的一个控制逻辑函数上配置一下:
    @RequestMapping("/all")
    //下面的注解的意思就是拥有/admin/all这个权限才能访问下面的这个控制器
    @PreAuthorize("hasAnyAuthority('/admin/all')")
    public ModelAndView all(@RequestParam(defaultValue = "1") int page,
                            @RequestParam(defaultValue = "10") int size){
        ModelAndView modelAndView=new ModelAndView();
        Page<Admin> adminPage=adminService.findPage(page,size);
        modelAndView.addObject("adminPage",adminPage);
        modelAndView.setViewName("/backstage/admin_all");
        return modelAndView;
    }然后依次在角色和权限的控制器中如此配置(都是在/all的控制器上配置),这样就可以实现不同权限的用户可以访问到的资源是不一样的,权限不够时就会出现提示权限不足的页面。

五.前端鉴权配置
先在common_aside.html(侧边栏文件)中引入命名空间(thymeleaf整合Spring Security)
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"如下配置,是有相应权限才会展示相应的模块。

不写了!Spring Security垃圾框架!RNM!!!



















