一文详细讲解SpringBoot 动态权限校验实现方案

1背景
简单先说一下需求吧,这样也好让看的人知道到底适不适合自己。

实现自定义的登录认证。
登录成功,生成token并将token 交由redis管理。
登录后对用户访问的接口进行接口级别权限认证。
springSecurity提供的注解权限校验适合的场景是系统中仅有固定的几个角色,且角色的凭证不可修改(如果修改需要改动代码)。

@PreAuthorize(“hasAuthority(‘ROLE_TELLER’)”)
public Account post(Account account, double amount);
注:ROLE_TELLER是写死的。

后端系统的访问请求有以下几种类型:

登录、登出(可自定义url)
匿名用户可访问的接口(静态资源,demo示例等)
其他接口(在登录的前提下,继续判断访问者是否有权限访问)
2环境搭建
依赖引入,包括springSecurity、redis、redis session需要的依赖:

org.springframework.boot spring-boot-starter-security 2.3.4.RELEASE org.springframework.session spring-session-data-redis 2.3.1.RELEASE org.springframework.boot spring-boot-starter-data-redis 2.3.4.RELEASE 注:springBoot版本也是2.3.4.RELEASE,如果有版本对应问题,自行解决。有用到swagger,为了便于测试。
新建springSecurity配置类
新建 WebSecurityConfig.java 继承自 WebSecurityConfigurerAdapter,过滤匿名用户可访问的接口。

WebSecurityConfig作为springSecurity的主配置文件。

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**

  • Swagger等静态资源不进行拦截
    /
    @Override
    public void configure(WebSecurity web) {
    web.ignoring().antMatchers(
    "/
    .html",
    “/favicon.ico”,
    “//*.html",
    "/
    /.css",
    "/**/
    .js”,
    “/error”,
    “/webjars/",
    "/resources/
    ”,
    “/swagger-ui.html”,
    “/swagger-resources/“,
    “/v2/api-docs”);
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
    //配置一些不需要登录就可以访问的接口
    .antMatchers(”/demo/
    ”, “/about/**”).permitAll()
    //任何尚未匹配的URL只需要用户进行身份验证
    .anyRequest().authenticated()
    .and()
    .formLogin()//允许用户进行基于表单的认证
    .loginPage(“/mylogin”);
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
}
图片
注:证明可以访问静态资源不会被拦截

自定义登录认证
springSecurity是基于过滤器进行安全认证的。

我们需要自定义:

登录过滤器:负责过滤登录请求,再交由自定义的登录认证管理器处理。
登录成功处理类:顾名思义,登录成功后的一些处理(设置返回信息提示“登录成功!”,返回数据类型为json)。
登录失败处理类:类似登录成功处理类。Ps:登录成功处理类和失败处理类有默认的实现可以不自定义。但是建议自定义,因为返回的信息为英文,一般情况不符合要求。
登录认证管理器:根据过滤器传过来的登录参数,进行登录认证,认证后授权。
新建登录成功处理类
需要实现 AuthenticationSuccessHandler

@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomAuthenticationSuccessHandler.class);

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
//登录成功返回的认证体,具体格式在后面的登录认证管理器中
String responseJson = JackJsonUtil.object2String(ResponseFactory.success(authentication));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(“登录成功!”);
}
response.getWriter().write(responseJson);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
}
新建登录失败处理类
实现 AuthenticationFailureHandler

@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomAuthenticationFailureHandler.class);

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {
String errorMsg;
if (StringUtils.isNotBlank(e.getMessage())) {
errorMsg = e.getMessage();
} else {
errorMsg = CodeMsgEnum.LOG_IN_FAIL.getMsg();
}
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
String responseJson = JackJsonUtil.object2String(ResponseFactory.fail(CodeMsgEnum.LOG_IN_FAIL,errorMsg));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(“认证失败!”);
}
response.getWriter().write(responseJson);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
}
新建登录认证管理器

实现 AuthenticationProvider ,负责具体的身份认证(一般数据库认证,在登录过滤器过滤掉请求后传入)

@Component
public class UserVerifyAuthenticationProvider implements AuthenticationProvider {
private PasswordEncoder passwordEncoder;
@Autowired
private UserService userService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String userName = (String) authentication.getPrincipal(); // Principal 主体,一般指用户名
String passWord = (String) authentication.getCredentials(); //Credentials 网络凭证,一般指密码
//通过账号去数据库查询用户以及用户拥有的角色信息
UserRoleVo userRoleVo = userService.findUserRoleByAccount(userName);
//数据库密码
String encodedP

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值