zoukankan      html  css  js  c++  java
  • Spring Security(二)

    本篇中加入了以下三个功能:

    1. 修改用户名密码的参数名称
    2. 通过自定义一个AuthenticationProvider在系统中加入一个后门
    3. 将验证身份信息展示到前端


    1.principal:身份 credentials:凭证 AuthenticationManager:身份验证管理类(它是验证管理类的总接口)ProviderManager类:(负责具体的验证管理)

    Spring Security主要包括两大功能:验证和鉴权。验证就是确认用户的身份,一般采用用户名和密码的形式;鉴权就是确认用户拥有的身份(角色、权限)能否访问受保护的资源。

    2.原理图


    3.参与验证的要素

    Spring Security不仅仅支持网页登录这一种验证模式,它还支持多种其他验证模式。但是其参与验证的要素基本上还是用户、密码、角色、受保护的资源这四种。

    用户名称一般在前端由访问者填入,而系统用户在后端一般存储在内存中或数据库中。

    密码一般在前端由访问者填入,用于验证用户身份,在Security 5.0后密码必须使用PasswordEncoder加密,一般来说使用BCryptPasswordEncoder即可。

    角色,又可以被看做权限,在Spring Security中,有时用Role表示,有时用Authority表示。前端一般看不到系统的角色。后端角色由管理者赋予给用户(可以事先赋予,也可以动态赋予),角色信息一般存储在内存或数据库中。

    受保护的资源,一般来说就是指网址,有时也可以将某些函数方法定义为资源,但本文不涉及这类情况.

    参与验证的要素(用户名、密码)在前端由表单提交,由网络传入后端后,会形成一个Authentication类的实例。该实例在进行验证前,携带了用户名、密码等信息;在验证成功后,则携带了身份信息、角色等信息。Authentication接口代码节选如下:

    public interface Authentication extends Principal, Serializable {
        Collection<? extends GrantedAuthority> getAuthorities();
        Object getCredentials();
        Object getDetails();
        Object getPrincipal();
        boolean isAuthenticated();
        void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
    }

    其中getCredentials()返回一个Object credentials,它代表验证凭据,即密码;getPrincipal()返回一个Object principal,它代表身份信息,即用户名等;getAuthorities()返回一个Collection<? extends GrantedAuthority>,它代表一组已经分发的权限,即本次验证的角色(本文中权限和角色可以通用)集合。

    有了Authentication实例,则验证流程主要围绕这个实例来完成。它会依次穿过整个验证链,并存储在SecurityContextHolder中。也可以像本文中的代码一样,在验证途中伪造一个Authentication实例,骗过验证流程,获得所有权限。

    4.验证的规则

    验证规则定义了以下几个东西:

    1. 受保护的资源即网址,它们一般按访问所需权限分为几类
    2. 哪一类资源可以由哪些角色访问
    3. 规则定义在WebSecurityConfigurerAdapter的子类中

    具体规则的定义方法可以在代码中观察

    5.验证流程

    前文已经介绍了Authentication类,它代表了验证信息。

    再介绍一个类AuthenticationManager,它是验证管理类的总接口;而具体的验证管理需要ProviderManager类,它具有一个List<AuthenticationProvider> providers属性,这实际上是一个AuthenticationProvider实例构成的验证链。链上都是各种AuthenticationProvider实例,这些实例进行具体的验证工作,它们之间的关系如下图(图来自互联网)所示:

    验证成功后,验证实例Authentication会被存入SecurityContextHolder中,而它则利用线程本地存储TLS功能。在验证成功且验证未过期的时间段内,验证会一直有效。而且,可以在需要的地方,从SecurityContextHolder中取出验证信息,并进行操作。例如将验证信息展示在前端。

    具体的验证流程如下:

    1. 后端从前端的表单得到用户密码,包装成一个Authentication类的对象;
    2. 将Authentication对象传给“验证管理器”ProviderManager进行验证;
    3. ProviderManager在一条链上依次调用AuthenticationProvider进行验证;
    4. 验证成功则返回一个封装了权限信息的Authentication对象(即对象的Collection<? extends GrantedAuthority>属性被赋值);
    5. 将此对象放入安全上下文SecurityContext中;
    6. 需要时,可以将Authentication对象从SecurityContextHolder上下文中取出。

    注意,在ProviderManager管理的验证链上,任何一个AuthenticationProvider通过了验证,则验证成功。所以,要在系统中留一个后门,只需要在代码中添加一个AuthenticationProvider的子类BackdoorAuthenticationProvider,并在输入特定的用户名(alex)时,直接伪造一个验证成功的Authentication,即可通过验证,代码如下:

    @Component
    public class BackdoorAuthenticationProvider implements AuthenticationProvider {
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            String name = authentication.getName();
            String password = authentication.getCredentials().toString();
    
            //利用alex用户名登录,不管密码是什么都可以,伪装成admin用户
            if (name.equals("alex")) {
                Collection<GrantedAuthority> authorityCollection = new ArrayList<>();
                authorityCollection.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
                authorityCollection.add(new SimpleGrantedAuthority("ROLE_USER"));
                return new UsernamePasswordAuthenticationToken(
                        "admin", password, authorityCollection);
            } else {
                return null;
            }
        }
    
        @Override
        public boolean supports(Class<?> authentication) {
            return authentication.equals(
                    UsernamePasswordAuthenticationToken.class);
        }
    }
    然后在SecurityConfiguration类中,将BackdoorAuthenticationProvider的实例加入到验证链中即可,代码如下:
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Autowired
        BackdoorAuthenticationProvider backdoorAuthenticationProvider;
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
           ...省略
            //将自定义验证类注册进去
            auth.authenticationProvider(backdoorAuthenticationProvider);
        }
      ...省略
    }

    6.将验证身份信息展示到前端

    前面已经提到,验证成功后,验证信息存入SecurityContextHolder中。因此可以在需要的地方,将其提取出来,然后在前端展示出来。

    后端代码:

    @Controller
    public class UserController {
    
        @RequestMapping("/user")
        public String user(@AuthenticationPrincipal Principal principal, Model model) {
            model.addAttribute("username", principal.getName());
    
            //从SecurityContextHolder中得到Authentication对象,进而获取权限列表,传到前端
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            Collection<GrantedAuthority> authorityCollection = (Collection<GrantedAuthority>) auth.getAuthorities();
            model.addAttribute("authorities", authorityCollection.toString());
            return "user/user";
        }
    
        @RequestMapping("/admin")
        public String admin(@AuthenticationPrincipal Principal principal, Model model) {
            model.addAttribute("username", principal.getName());
    
            //从SecurityContextHolder中得到Authentication对象,进而获取权限列表,传到前端
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            Collection<GrantedAuthority> authorityCollection = (Collection<GrantedAuthority>) auth.getAuthorities();
            model.addAttribute("authorities", authorityCollection.toString());
            return "admin/admin";
        }
    }






    1

  • 相关阅读:
    如何得到数据绑定的树节点的父节点
    ImageBrush中的图片如何加载到到MemoryStream
    C#中动态加载和卸载DLL
    SetProcessWorkingSetSize减少内存占用
    wpf中如何改变Listbox选中项的颜色
    怎样把Visual Studio与Perforce关联起来
    在WPF里面如何使用FolderBrowserDialog
    关于WPF的ComboBox中Items太多而导致加载过慢的问题(转载)
    得到系统中所有正打开的文件
    把ResourceDictionary保存为文件,从外部xaml文件加载ResourceDictionary
  • 原文地址:https://www.cnblogs.com/xc-xinxue/p/12500531.html
Copyright © 2011-2022 走看看