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();
    }
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中找到

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

 

posted @ 2019-06-23 17:09  jiataoqin  阅读(254)  评论(0编辑  收藏  举报