前面我们弄好了认证,授权就是在认证的基础之上

授权

只有用户认证了才可能有授权,授权就是当前用户能干什么

UserDetailServiceImpl

	// 之前我们只是在这里将用户的一些基本信息封装了,但是我们要授权的话需要角色信息和权限信息
	// TODO 添加持久层的代码 获取当前用户的角色和权限信息

TokenFilter

	// 在对UsernamePasswordAuthenticationToken封装的时候,没有将对象中的权限封装进去

	// TODO 调用UserDetail中的getAuthorities方法,这个方法返回GrantedAuthority
	UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, null,loginUser.getAuthorities());
       

启动类

添加@EnableGlobalMethodSecurity(prePostEnabled = true)注解

Controller

在Controller层中的方法上添加 @PreAuthorize("hasAuthority('权限名')") @PreAuthorize("hasAuthority('权限名')") 用户有这个权限才能访问 @PreAuthorize("hasRole('角色名')") 用户是当前角色才能访问

RBAC模型

基于角色进行权限控制,这个时候我们不关心当前用户有哪些权限。只用关系当前用户有哪些角色

RBAC表设计

  1. tb_security_user_role
    • id
    • user_id
    • role_id
  2. tb_security_role
    • id
    • role_name
  3. tb_security_role_permission
    • id
    • role_id
    • permission_id
  4. tb_security_permission
    • id
    • permission_name

其他

自定义处理异常

当发送异常的时候,SepringSecurity会自动处理掉。因为我们是前后端分离我们不用管处理的逻辑只用返回一个Result的json字符串返回给前端,前端自己处理

{
	"code" : "xxx",
	"msg"  : "xxx",
	"status" : "xxx",
	"data" : [
		"key" : "value"
	]
}

自定义处理认证时发送的异常

@Component
// 认证期间异常处理
public class AuthenticationExceptionHandler implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        Result result = Result.fail().data("msg", authException.getMessage());
        String resultJSON = JSONUtil.toJsonStr(result);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter writer = response.getWriter();

        writer.append(resultJSON);

    }
}

自定义授权时发生的异常

@Component
// 处理授权异常的
public class AuthorizationExceptionHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        Result result = Result.fail().data("msg", accessDeniedException.getMessage());
        String resultJSON = JSONUtil.toJsonStr(result);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter writer = response.getWriter();

        writer.append(resultJSON);
    }
}

将自定义的处理异常对象添加到配置类中 SecurityConfig

 	// 自定义异常处理
        http.exceptionHandling()
                .authenticationEntryPoint(authenticationExceptionHandler)
                .accessDeniedHandler(authorizationExceptionHandler);

跨域

解决Spring Security跨域 SecurityConfig

  	// 跨域
        http.cors();

解决MVC跨域

@Configuration
public class CorsConfig {

    @Bean
    public CorsConfigurationSource corsFilterConfiguration() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOrigin("*"); // 允许所有源
        configuration.addAllowedHeader("*"); // 允许所有请求头
        configuration.addAllowedMethod("*"); // 允许所有请求方法
        configuration.setAllowCredentials(true); // 允许发送凭证
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration); // 对所有URL生效
        return source;
    }
}