Spring Security的授权管理器
当用户登录以后,携带了token访问后端,那么此时Spring Security框架就要对当前请求进行验证,验证包含了两部分,第一验证携带的token是否合法,第二验证当前用户是否拥有当前访问资源的权限。
1. 整体实现思路
暂时无法在飞书文档外展示此内容
- 403错误:表示请求需要授权,前端一般会提示没有权限访问
2. 自定义授权管理器
我们创建一个类:TokenAuthorizationManager ,这个类有两个要求
- 被spring容器进行管理,所以需要添加@Component注解
- 实现AuthorizationManager<RequestAuthorizationContext>接口,并重写check方法,在方法中编写校验逻辑
package com.itheima.project.config; import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.itheima.project.util.JwtUtil; import com.itheima.project.vo.UserAuth; import io.jsonwebtoken.Claims; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.access.intercept.RequestAuthorizationContext; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.util.function.Supplier; /** * @author sjqn */ @Component public class TokenAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> { @Override public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) { //获取request HttpServletRequest request = requestAuthorizationContext.getRequest(); //获取用户当前的请求地址 String requestURI = request.getRequestURI(); //获取token String token = request.getHeader("token"); if(null == token || "".equals(token)){ return new AuthorizationDecision(false); } //解析token Claims claims = JwtUtil.parseJWT("itcast", token); if (ObjectUtil.isEmpty(claims)) { //token失效 return new AuthorizationDecision(false); } //获取userAuth UserAuth userAuth = JSONObject.parseObject(JSON.toJSONString(claims.get("user")),UserAuth.class); //存入上下文 UsernamePasswordAuthenticationToken auth =new UsernamePasswordAuthenticationToken( userAuth, userAuth.getPassword(), userAuth.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(auth); //判断地址与对象中的角色是否匹配 if(userAuth.getRoles().contains("ADMIN")){ if("/hello/admin".equals(requestURI)){ return new AuthorizationDecision(true); } } if(userAuth.getRoles().contains("USER")){ if("/hello/user".equals(requestURI)){ return new AuthorizationDecision(true); } } return new AuthorizationDecision(false); } }
3. 注册授权管理器
授权管理器想要生效需要在SecurityConfig中进行注册才能使用
package com.itheima.project.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; /** * @author sjqn */ @Configuration public class SecurityConfig { @Autowired private TokenAuthorizationManager tokenAuthorizationManager; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests().antMatchers("/security/login").permitAll() .anyRequest().access(tokenAuthorizationManager); //关闭session http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); //关闭缓存 http.headers().cacheControl().disable(); http.csrf().disable(); //返回 return http.build(); } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
4. 测试
重启项目之后可以采用postman或者apifox进行测试
- 测试一:
- 登录账号:user@qq.com 拥有角色:USER
- 可以访问:/hello/user
- 其他请求返回403
- 测试二:
- 登录账号:admin@qq.com 拥有角色:USER、ADMIN
- 可以访问:/hello/user、/hello/user