SpringSecurity详解

工作流程

51

SecurityContextHolder

SecurityContextHolder 是最基本的对象,它负责存储当前安全上下文信息。即保存着当前用户是什么,是否已经通过认证,拥有哪些权限。。。等等。

Spring Security使用一个Authentication对象来表示这些信息。通常不需要自己创建一个Authentication对象,但可以在程序的任何一个地方获取到用户信息,下面时官方提供的获取用户信息:

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}

Authentication

package org.springframework.security.core;// <1>

public interface Authentication extends Principal, Serializable { // <1>
    Collection<? extends GrantedAuthority> getAuthorities(); // <2>

    Object getCredentials();// <2>

    Object getDetails();// <2>

    Object getPrincipal();// <2>

    boolean isAuthenticated();// <2>

    void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

getAuthorities,权限列表,通常是代表权限的字符串列表;
getCredentials,密码信息,由用户输入的密码凭证,认证之后会移出,来保证安全性;
getDetails,细节信息,Web应用中一般是访问者的ip地址和sessionId;
getPrincipal, 最重要的身份信息,一般返回UserDetails的实现类

UserDetails 和 UserDetailsService

UserDetails接口代表了最详细的用户信息,这个接口涵盖了一些必要的用户信息字段,具体的实现类对它进行了扩展。

它和Authentication接口类似,都包含了用户名,密码以及权限信息,而区别就是Authentication中的getCredentials来源于用户提交的密码凭证,而UserDetails中的getPassword取到的则是用户正确的密码信息,认证的第一步就是比较两者是否相同,除此之外,Authentication中的getAuthorities是认证用户名和密码成功之后,由UserDetails中的getAuthorities传递而来。而Authentication中的getDetails信息是经过了AuthenticationProvider认证之后填充的。

public interface UserDetails extends Serializable {

   Collection<? extends GrantedAuthority> getAuthorities();

   String getPassword();

   String getUsername();

   boolean isAccountNonExpired();

   boolean isAccountNonLocked();

   boolean isCredentialsNonExpired();

   boolean isEnabled();
}

UserDetailsService 只有一个方法,就是从特定的地方(一般是从数据库中)加载用户信息,仅此而已。

public interface UserDetailsService {
   UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

AuthenticationManager

AuthenticationManager接口只包含一个方法,那就是认证,它是认证相关的核心接口,也是发起认证的出发点。

public interface AuthenticationManager {
    Authentication authenticate(Authentication authentication)
            throws AuthenticationException;
}

Spring推荐通过实现AuthenticationManager接口来自定义自己的认证方式.Spring提供了一个默认的实现,ProviderManager。

AuthenticationProvider

public interface AuthenticationProvider {

    Authentication authenticate(Authentication authentication)
            throws AuthenticationException;

    boolean supports(Class<?> authentication);
}

Spring 提供了几种AuthenticationProvider的实现:

DaoAuthenticationProvider从数据库中读取用户信息验证身份
AnonymousAuthenticationProvider匿名用户身份认证
RememberMeAuthenticationProvider已存cookie中的用户信息身份认证
AuthByAdapterProvider使用容器的适配器验证身份
CasAuthenticationProvider根据Yale中心认证服务验证身份,用于实现单点登陆
JaasAuthenticationProvider从JASS登陆配置中获取用户信息验证身份
RemoteAuthenticationProvider根据远程服务验证用户身份
RunAsImplAuthenticationProvider对身份已被管理器替换的用户进行验证
X509AuthenticationProvider从X509认证中获取用户信息验证身份
TestingAuthenticationProvider单元测试时使用

注解

Spring Security默认是禁用注解的,要想开启注解, 需要在继承WebSecurityConfigurerAdapter的类上加@EnableGlobalMethodSecurity注解,来判断用户对某个控制层的方法是否具有访问权限 。

@EnableGlobalMethodSecurity

1、@EnableGlobalMethodSecurity(securedEnabled=true) 开启@Secured 注解过滤权限

2、@EnableGlobalMethodSecurity(jsr250Enabled=true)开启@RolesAllowed 注解过滤权限

3、@EnableGlobalMethodSecurity(prePostEnabled=true) 开启@PreAuthorize,@PostAuthorize注解过滤权限

@PreAuthorize、@PostAuthorize

@GetMapping("/helloUser")
@PreAuthorize("hasAnyRole('normal','admin')")
public String helloUser() {
    return "hello,user";
}
拥有normal或者admin角色的用户都可以方法helloUser()方法。

@GetMapping("/helloUser")
@PreAuthorize("hasRole('normal') AND hasRole('admin')") 
public String helloUser() {
    return "hello,user";
}
必须同时拥有normal和admin才可以使用
@PostAuthorize 注解使用并不多,在方法执行后再进行权限验证,适合验证带有返回值的权限

@GetMapping("/helloUser")
@PostAuthorize(" returnObject!=null &&  returnObject.username == authentication.name")
public User helloUser() {
        Object pricipal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        User user;
        if("anonymousUser".equals(pricipal)) {
            user = null;
        }else {
            user = (User) pricipal;
        }
        return user;
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×