spring security使用和原理简析

Posted jiataoq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring security使用和原理简析相关的知识,希望对你有一定的参考价值。

主要参考: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();
    
View Code

 

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);
        
    
View Code

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");
    
View Code

 

登录接口

技术图片
    @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");
    
View Code

 

完整的项目代码,除了登录可以在https://github.com/527515025/springBoot中的springboot-SpringSecurity3中找到

以上就实现了用户、角色、权限的动态管理,接下来我们简单的探究一下原理

 

以上是关于spring security使用和原理简析的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security sec:使用 Java Config 授权标签

如何在 Spring Security thymeleaf sec 中使用列表:授权标签

Spring Security sec:授权抛出异常

Spring Security - Thymeleaf - 我可以在 sec:authorize 标签中评估 SPEL 表达式吗?

sec:authorize 对 Spring Security 不起作用

我在这里使用 Struts 2 和 Spring Security Integration