一.编写相关页面
在本项目中,我们使用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!!!