0


【SpringSecurity】之授权的使用案例

一、引言

1、什么是SpringSecurity授权

Spring Security授权是指基于Spring Security框架的访问控制过程。授权是指根据系统提前设置好的规则,给用户分配可以访问某一个资源的权限,用户根据自己所具有的权限,去执行相应操作。在Spring Security中,授权通常与身份验证一起使用,以确保只有经过身份验证的用户才能访问特定的资源。

Spring Security授权的核心概念包括:

  1. 认证:身份认证,即判断一个用户是否为合法用户的处理过程。Spring Security支持多种不同方式的认证,但无论使用哪种方式,都不会影响授权功能的使用。因为Spring Security很好地做到了认证和授权的解耦。
  2. 授权:访问控制,即控制谁能访问哪些资源。简单的理解就是根据系统提前设置好的规则,给用户分配可以访问某一个资源的权限,用户根据自己所具有的权限,去执行相应操作。

在Spring Security中,授权通常通过安全配置类来实现。这个类定义了哪些URL需要授权以及如何处理安全相关的异常。它使用过滤器链来拦截请求并检查用户的权限。如果用户通过了身份验证并且具有访问特定资源的权限,他们就可以成功访问该资源。

2、授权介绍

Spring Security 中的授权分为两种类型:

  • 基于角色的授权:以用户所属角色为基础进行授权,如管理员、普通用户等,通过为用户分配角色来控制其对资源的访问权限。
  • 基于资源的授权:以资源为基础进行授权,如 URL、方法等,通过定义资源所需的权限,来控制对该资源的访问权限。

Spring Security 提供了多种实现授权的机制,最常用的是使用基于注解的方式,建立起访问资源权限之间的映射关系。

其中最常用的两个注解是

@Secured

@PreAuthorize

@Secured

注解是更早的注解,基于角色的授权比较适用,

@PreAuthorize

基于

SpEL

表达式的方式,可灵活定义所需的权限,通常用于基于资源的授权。

二、SpringSecurity授权

根据 【Spring Security】认证之案例的使用、MD5加密、CSRF防御中表设计进行加强

1、修改User配置角色和权限

定义

SQL

语句,根据用户ID查询角色和角色对应的权限。

  • 根据用户ID查询出用户对应的角色信息。
SELECT
    r.rolename    
FROM
    sys_user u,sys_user_role ur,sys_role r
where
    u.id=ur.userid and ur.roleid=r.roleid and u.id=#{userid}
  • 根据用户ID查询出角色对应的权限信息。
select
    m.url
from
    sys_user u,sys_user_role ur,sys_role r,sys_role_module rm,sys_module m
where
    u.id=ur.userid and ur.roleid=r.roleid and
    r.roleid=rm.roleid and rm.moduleid=m.id and
    u.id=#{userid} and url is not null

修改User实体类,添加角色和权限集合,并完成角色和权限的数据填充。

@Getter@Setter@Accessors(chain =true)@TableName("sys_user")publicclassUserimplementsSerializable,UserDetails{privatestaticfinallong serialVersionUID =1L;/**
     * 主键
     */@TableId(value ="id", type =IdType.AUTO)privateInteger id;/**
     * 用户名
     */@TableField("username")privateString username;/**
     * 密码
     */@TableField("password")privateString password;/**
     * 真实姓名
     */@TableField("real_name")privateString realName;/**
     * 是否过期
     */@TableField("account_non_expired")privateboolean accountNonExpired;/**
     * 权限
     */@TableField(exist =false)privateList<?extendsGrantedAuthority> authorities;/**
     * 是否锁定
     */@TableField("account_non_locked")privateboolean accountNonLocked;/**
     * 是否过期
     */@TableField("credentials_non_expired")privateboolean credentialsNonExpired;/**
     * 是否启用
     */@TableField("enabled")privateboolean enabled;}

2、修改loadUserByUsername方法

@ServicepublicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsUserService,UserDetailsService{@AutowiredprivateRoleMapper roleMapper;@AutowiredprivateRoleModuleMapper roleModuleMapper;@OverridepublicUserDetailsloadUserByUsername(String username)throwsUsernameNotFoundException{//根据用户名查询数据库中用户信息User user =this.getOne(newQueryWrapper<User>().eq("username", username));//判断用户是否存在if(Objects.isNull(user))thrownewUsernameNotFoundException("用户不存在");//权限校验TODO,后续讲解List<String> roles = roleMapper.queryRolesByUid(user.getId());List<String> permission = roleModuleMapper.queryRoleModuleByUid(user.getId());
        user.setRoles(roles);
        user.setPermissions(permission);return user;}}

3、修改SpringSecurity配置类

当我们想要开启

spring

方法级安全时,只需要在任何

@Configuration

实例上使用

@EnableGlobalMethodSecurity

注解就能达到此目的。同时这个注解为我们提供了

prePostEnabled

securedEnabled

jsr250Enabled

三种不同的机制来实现同一种功能。

修改

WebSecurityConfig

配置类,开启基于方法的安全认证机制,也就是说在web层的controller启用注解机制的安全确认。

@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled =true)publicclassWebSecurityConfig{//@Autowired 注解用于标注在需要进行依赖注入的属性或方法上@AutowiredprivateMyUserDetailsService userDetailsService;@AutowiredprivateObjectMapper objectMapper;@AutowiredprivateMyAuthenticationFailureHandler myAuthenticationFailureHandler;@Bean//@Bean 注解用于标注在需要进行依赖注入的属性或方法上publicPasswordEncoderpasswordEncoder(){//BCryptPasswordEncoder 用于对密码进行编码returnnewBCryptPasswordEncoder();}@BeanpublicAuthenticationManagerauthenticationManager()throwsException{// 创建一个DaoAuthenticationProvider对象DaoAuthenticationProvider provider =newDaoAuthenticationProvider();// 设置用户详情服务和密码编码器
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder());// 返回一个ProviderManager对象returnnewProviderManager(provider);}@BeanpublicSecurityFilterChainsecurityFilterChain(HttpSecurity http)throwsException{
        http.authorizeRequests()// 允许所有用户访问根路径.antMatchers("/").permitAll()// 允许管理员访问管理员路径.antMatchers("/admin/**").hasRole("ADMIN")// 允许管理员和用户访问用户路径.antMatchers("/user/**").hasAnyRole("ADMIN","USER")// 需要身份认证 anyRequest 其余所有请求 & authenticated 登录.anyRequest().authenticated().and().formLogin()//loginPage 登录页面.loginPage("/")//设置处理登录请求的接口.loginProcessingUrl("/userLogin")//用户的数据的参数.usernameParameter("username").passwordParameter("password")//登录成功.successHandler((req, resp, auth)->{//获取用户信息Object user = auth.getPrincipal();//返回json格式的用户信息
                    objectMapper
                            .writeValue(resp.getOutputStream(),JsonResponseBody.success(user));})//登录失败.failureHandler(myAuthenticationFailureHandler).and().exceptionHandling()//权限不足.accessDeniedHandler((req, resp, ex)->{//返回json格式的无权限信息
                    objectMapper
                            .writeValue(resp.getOutputStream(),JsonResponseBody.other(JsonResponseStatus.NO_ACCESS));})//没有认证.authenticationEntryPoint((req, resp, ex)->{//返回json格式的未登录信息
                    objectMapper
                            .writeValue(resp.getOutputStream(),JsonResponseBody.other(JsonResponseStatus.NO_LOGIN));}).and().logout()//设置登出url.logoutUrl("/logout")//设置登出成功url.logoutSuccessUrl("/");//禁用csrf
        http.csrf().disable();//返回http实例return http.build();}}
@EnableGlobalMethodSecurity

是Spring Security提供的一个注解,用于启用方法级别的安全性。它可以在任何@Configuration类上使用,以启用Spring Security的方法级别的安全性功能。它接受一个或多个参数,用于指定要使用的安全注解类型和其他选项。以下是一些常用的参数:

  • prePostEnabled:如果设置为true,则启用@PreAuthorize@PostAuthorize注解。默认值为false
  • securedEnabled:如果设置为true,则启用@Secured注解。默认值为false
  • jsr250Enabled:如果设置为true,则启用@RolesAllowed注解。默认值为false
  • proxyTargetClass:如果设置为true,则使用CGLIB代理而不是标准的JDK动态代理。默认值为false

使用

@EnableGlobalMethodSecurity

注解后,可以在应用程序中使用Spring Security提供的各种注解来保护方法,例如

@Secured

@PreAuthorize

@PostAuthorize

@RolesAllowed

。这些注解允许您在方法级别上定义安全规则,以控制哪些用户可以访问哪些方法。

注解介绍:
注解说明

@PreAuthorize

用于在方法执行之前对访问进行权限验证

@PostAuthorize

用于在方法执行之后对返回结果进行权限验证

@Secured

用于在方法执行之前对访问进行权限验证

@RolesAllowed

是Java标准的注解之一,用于在方法执行之前对访问进行权限验证

4、控制Controller层接口权限

@RestController@RequestMapping("/user")publicclassUserController{@AutowiredprivateRoleService roleService;@AutowiredprivateModuleService moduleService;@RequestMapping("/userLogin")publicStringuserLogin(User user){return"login";}@PreAuthorize("hasAuthority('order:manager:list')")@GetMapping("/queryRoles")publicJsonResponseBody<List<Role>>queryRoles(){List<Role> list = roleService.list();returnnewJsonResponseBody<>(list);}@PreAuthorize("hasAuthority('book:manager:list')")@GetMapping("/queryModules")publicJsonResponseBody<List<Module>>queryModules(){List<Module> list = moduleService.list();returnnewJsonResponseBody<>(list);}@PreAuthorize("hasAuthority('管理员')")@GetMapping("/queryTest")publicJsonResponseBody<?>queryTest(){returnnewJsonResponseBody<>("你好,我是管理员!");}}

更多常见内置表达式见官方文档

5、启动测试

配置完毕之后,重新启动项目。分别使用两个不同的用户(

admin

zs

)登录进行权限测试。
在这里插入图片描述

注意:

admin

具备所有权限;

zs

只具备部分权限。

当通过

zs

用户登录成功之后,点击权限和角色验证进行权限测试。

  • 点击获取用户角色信息,可以成功显示数据:
  • 点击获取角色权限信息,提示403错误:(也就是无权限提示)

6、异常处理

①AccessDeniedHandler

AccessDeniedHandler

是Spring Security提供的一个接口,用于处理访问被拒绝的情况。当用户尝试访问受保护资源但没有足够的权限时,Spring Security会调用

AccessDeniedHandler

来处理这种情况。

AccessDeniedHandler

接口只有一个方法

handle()

,该方法接收

HttpServletRequest

HttpServletResponse

AccessDeniedException

三个参数。在

handle()

方法中,可以自定义响应的内容,例如返回一个自定义的错误页面或

JSON

响应。

创建

AccessDeniedHandlerImpl

类并实现

AccessDeniedHandler

接口,实现自定义的

JSON

响应。例如:

@ComponentpublicclassAccessDeniedHandlerImplimplementsAccessDeniedHandler{@Overridepublicvoidhandle(HttpServletRequest request,HttpServletResponse response,AccessDeniedException accessDeniedException)throwsIOException,ServletException{int code =500;
        response.setStatus(200);
        response.setContentType("application/json;charset=UTF-8");String msg ="权限不足,无法访问系统资源";Map<String,Object> result =newHashMap<>();
        result.put("msg", msg);
        result.put("code", code);String s =newObjectMapper().writeValueAsString(result);
        response.getWriter().println(s);}}

然后,将自定义的

accessDeniedHandler

注入到

Spring Security

的配置中:

@AutowiredprivateAccessDeniedHandlerImpl accessDeniedHandler;@BeanpublicSecurityFilterChainsecurityFilterChain(HttpSecurity http)throwsException{return
        http
        // ....exceptionHandling().accessDeniedHandler(accessDeniedHandler())// ...}

这样,当访问被拒绝时,

Spring Security

就会调用自定义

AccessDeniedHandler

来处理。

②AuthenticationEntryPoint

AuthenticationEntryPoint

是Spring Security中的一个接口,用于定义如何处理未经身份验证的请求。当用户尝试访问需要身份验证的资源但未进行身份验证时,

AuthenticationEntryPoint

将被调用。

在这个接口中,可以自定义如何处理这些未经身份验证的请求,例如重定向到登录页面或返回错误消息。需要注意的是,

AuthenticationEntryPoint

只处理未经身份验证的请求,已经进行身份验证但权限不足的请求则需要使用

AccessDeniedHandler

来处理。

创建

AuthenticationEntryPointImpl

类并实现

AuthenticationEntryPoint

接口,实现自定义的

JSON

响应。例如:

@ComponentpublicclassAuthenticationEntryPointImplimplementsAuthenticationEntryPoint{@Overridepublicvoidcommence(HttpServletRequest request,HttpServletResponse response,AuthenticationException authException)throwsIOException,ServletException{
        response.setStatus(200);int code =500;String msg ="认证失败,无法访问系统资源";
        response.setContentType("application/json;charset=UTF-8");Map<String,Object> result =newHashMap<>();
        result.put("msg", msg);
        result.put("code", code);String s =newObjectMapper().writeValueAsString(result);
        response.getWriter().println(s);}}

然后,将自定义的

authenticationEntryPoint

注入到

Spring Security

的配置中:

@AutowiredprivateAuthenticationEntryPointImpl authenticationEntryPoint;@BeanpublicSecurityFilterChainsecurityFilterChain(HttpSecurity http)throwsException{return
        http
        // ....exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)// ...}

这样,当认证失败时,

Spring Security

就会调用自定义

AuthenticationEntryPoint

来处理。

标签: java 数据库 前端

本文转载自: https://blog.csdn.net/weixin_74383330/article/details/135278421
版权归原作者 无法自律的人 所有, 如有侵权,请联系我们删除。

“【SpringSecurity】之授权的使用案例”的评论:

还没有评论