spring security使用和原理简析(1)
主要参考:https://blog.csdn.net/u012373815/article/details/55225079
源码参考:https://github.com/527515025/springBoot
项目需求
1:实现了用户、角色、权限的动态管理,可以管控到接口地址,已经访问方式(get,post)
2:自定义登录接口
3:结合spring-session,来保存用户登录信息
表结构说明
method来控制相同方法名的不同访问方式(get,post,put等)
项目结构
废话不多说,看一下实现功能的核心代码
SecurityConfig核心方法
protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() //访问未授权资源的异常,403 .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() //登录后访问未配置权限资源的异常,401 .exceptionHandling().accessDeniedHandler(accessDeniedHandler).and() .authorizeRequests() //匿名用户也可以访问的资源 .antMatchers("/api/v1/auth").permitAll() .antMatchers("/logout").permitAll() .antMatchers("/**","/swagger-resources/**","/translate_a/**","/doc.html", "/webjars/**", "/v2/**", "/META-INF/resources/webjars/","/META-INF/resources/").permitAll() .anyRequest().authenticated() .and() //开启session,同时只能登录一个用户 .sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry) .and() .and() .logout().logoutUrl("/api/v1/logout") .invalidateHttpSession(true) .clearAuthentication(true) .and() .httpBasic(); }
UrlFilterSecurityInterceptor核心方法
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public void invoke(FilterInvocation fi) throws IOException, ServletException { //fi里面有一个被拦截的url //里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限 //再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够 InterceptorStatusToken token = super.beforeInvocation(fi); try { //执行下一个拦截器 fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.afterInvocation(token, null); } }
UrlAccessDecisionManager核心方法
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { HttpServletRequest request = ((FilterInvocation) object).getHttpRequest(); String url, method; //关闭鉴权 if (true){ return; } //放行在config中配置的无需登录就能访问的资源 if ( matchers("/api/v1/auth", request) || matchers("/swagger-resources/**", request) || matchers("/translate_a/**", request) || matchers("/doc.html", request) || matchers("/webjars/**", request) || matchers("/v2/**", request) || matchers("/META-INF/resources/webjars/**", request) || matchers("/META-INF/resources/**", request)) { return; } else { //匹配用户所具有的接口访问权限 for (GrantedAuthority ga : authentication.getAuthorities()) { if (ga instanceof UrlGrantedAuthority) { UrlGrantedAuthority urlGrantedAuthority = (UrlGrantedAuthority) ga; url = urlGrantedAuthority.getPermissionUrl(); method = urlGrantedAuthority.getMethod(); if (matchers(url, request)) { if (method.equals(request.getMethod()) || "ALL".equals(method)) { return; } } } } } throw new AccessDeniedException("no right"); }
登录接口
@PostMapping("/auth") @ApiOperation(value = "用户登录接口") public ApiResponse<String> auth(HttpServletRequest request,@RequestBody ReqLoginDto reqLoginDto){ SysUser user= userService.login(reqLoginDto.getUserName(), reqLoginDto.getPassword()); //todo 异常捕获,返回错误信息 if (user==null) { return ApiResponse.error("异常","登录异常"); } //加载用户信息及权限 UserDetails userDetails = customUserService.loadUserByUsername(user.getUsername()); //生成满足spring security框架要求的登录信息 UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); //保存在当前请求的SecurityContextHolder中 SecurityContextHolder.getContext().setAuthentication(authentication); return ApiResponse.ok("success"); }
完整的项目代码,除了登录可以在https://github.com/527515025/springBoot中的springboot-SpringSecurity3中找到
以上就实现了用户、角色、权限的动态管理,接下来我们简单的探究一下原理