Spring Boot整合Spring Security简记-高级认证(二)

new無语 转载请注明原创出处,谢谢!

Spring Security学习目录

上章硬编码了一个user用户。记录一点基础的配置,这次结合高级认证灵活使用Spring Security的用户认证。

  • AuthenticationManager: 身份验证的主要策略设置接口
  • ProviderManager: AuthenticationManager最常用的接口实现
  • AuthenticationProvider: ProviderManager的工作被委托者
  • Authentication: 认证用户信息主体
  • GrantedAuthority: 用户主体的权限
  • UserDetails: 用户的基本必要信息
  • UserDetailsService: 通过String username返回一个UserDetails

  • SecurityContextHolder: 提供访问 SecurityContext
  • SecurityContext: 保存Authentication,和一些其它的信息

1. AuthenticationProvider

ProviderManager把工作委托给AuthenticationProvider集合。ProviderManager将所有AuthenticationProvider进行循环,直到运行返回一个完整的Authentication,不符合条件或者不能认证当前Authentication,返回AuthenticationException异常或者null

@Component
public class SpringAuthenticationProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication, "非验证类型");
        //账号
        String username = authentication.getName();
        //密码
        String password = authentication.getCredentials().toString();
        List roles = new ArrayList<>();
        if("testuser1".equalsIgnoreCase(username)){
            roles.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        }else if("testuser2".equalsIgnoreCase(username)){
            roles.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
            roles.add(new SimpleGrantedAuthority("ROLE_DBA"));
        }else{
            throw new UsernameNotFoundException("用户名/密码无效");
        }
        return new UsernamePasswordAuthenticationToken(username, password, roles);
    }

    @Override
    public boolean supports(Class authentication) {
        return (UsernamePasswordAuthenticationToken.class
                .isAssignableFrom(authentication));
    }
}

此情况在AuthenticationManagerBuilder没有配置的情况下生效。(要把配置文件配置的用户账号/密码/角色配置信息注释掉)
CollectionAuthentication的角色信息。在认证成功返回时添加到Authentication中。
supports(Class authentication)方法是判断是否支持当前Authentication类型的认证。(JaasAuthenticationTokenOAuth2AuthenticationUsernamePasswordAuthenticationToken、自己实现)等。
上面定义了两个用户,分别是testuser1testuser2,分别赋权ADMINROLE_ADMIN+ROLE_DBA(符合上章的权限请求路径)(Spring Security拦截器角色验证前缀"ROLE_")。
运行项目进行测试角色是否正确。http://localhost:8080/login进行登录,分别访问http://localhost:8080/db/123http://localhost:8080/admin/123 返回404(有权限访问)或者403(无权限访问)。

2. UserDetailsService

实现UserDetailsService方法,提供UserDetails
我们把上面的用户登录的查询功能挪动到UserDetailsSerivce接口实现中。

@Service
public class SpringUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserDetails userDetails = null;
        List roles = new ArrayList<>();
        if ("testuser1".equalsIgnoreCase(username)) {
            roles.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        } else if ("testuser2".equalsIgnoreCase(username)) {
            roles.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
            roles.add(new SimpleGrantedAuthority("ROLE_DBA"));
        } else {
            return null;
        }
        userDetails = new User(username, "password", roles);
        return userDetails;
    }
}

之后再对认证代码进行改动。

@Component
public class SpringAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication, "非验证类型");
        //账号
        String username = authentication.getName();
        //密码
        String password = authentication.getCredentials().toString();
        List roles = new ArrayList<>();
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if (userDetails == null) {
            throw new UsernameNotFoundException("用户名/密码无效");
        }
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password, roles);
        token.setDetails(userDetails);
        return token;
    }

    @Override
    public boolean supports(Class authentication) {
        return (UsernamePasswordAuthenticationToken.class
                .isAssignableFrom(authentication));
    }
}

3. PasswordEncoder

Spring Security提供了很多加密方式,MD5、SHA、BCrypt等,官方推荐使用BCrypt,好处就不在这说了。自己百度下吧。提供的支持类就是BCryptPasswordEncoder。使用方式简单,直接初始化。注入就可以用了。两个方法加密、解密。
PasswordEncoder

/**
     * Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or
     * greater hash combined with an 8-byte or greater randomly generated salt.
     */
    String encode(CharSequence rawPassword);

    /**
     * Verify the encoded password obtained from storage matches the submitted raw
     * password after it too is encoded. Returns true if the passwords match, false if
     * they do not. The stored password itself is never decoded.
     *
     * @param rawPassword the raw password to encode and match
     * @param encodedPassword the encoded password from storage to compare with
     * @return true if the raw password, after encoding, matches the encoded password from
     * storage
     */
    boolean matches(CharSequence rawPassword, String encodedPassword);

你可能感兴趣的:(Spring Boot整合Spring Security简记-高级认证(二))