IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring Boot Security配置用户认证和资源授权 -> 正文阅读

[Java知识库]Spring Boot Security配置用户认证和资源授权

用户认证

认证是指,用户是否在本系统,以及账号信息是否符合设定的预期。

查询用户(UserDetailsService)

实现UserDetailsService接口,根据用户名称,查询用户信息。可实现自定义查询用户,并设置用户的角色信息。

实现了该接口,需要到配置对应的密码加密类已实现对用户密码的校验。因前端输入的密码是未加密,而数据库保存的密码是已加密的。

@Service
public class CustomerUserDetailsService implements UserDetailsService {
    //密码加密类
	@Autowired
    private PasswordEncoder passwordEncoder;
    //加载用户信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        CustomerUserDetails userDetails = new CustomerUserDetails();
        userDetails.setUsername("user");
        userDetails.setPassword(passwordEncoder.encode("123123"));
        userDetails.setEnable(true);
        userDetails.setAuthorities(Collections.emptySet());
        userDetails.setAccountNonExpired(true);
        userDetails.setAccountNonLocked(true);
        userDetails.setCredentialsNonExpired(true);
        return userDetails;
    }

      /**
     * 根据用户名,返回用户角色
     */
    private Collection<? extends GrantedAuthority> loadRoleByUsername(String username){
        Collection<SimpleGrantedAuthority> collection = new HashSet<>();
        //测试数据
        if("admin".equals(username)) {
            collection.add(new SimpleGrantedAuthority("ADMIN"));
        }else {
            collection.add(new SimpleGrantedAuthority(username));
        }
        return collection;
    }

    /**
     * 角色信息可以参考SimpleGrantedAuthority类
     * 根据用户名, 返回用户组角色
     */
    private void loadGroupRoleByUsername(String username){

    }
}

用户信息(UserDetails)

只需要实现UserDetails接口即可,自定义参数不需要和接口调用类保持一致(set/get)但最好保持一致,该接口是UserDetailsService接口中返回参数。

public class CustomerUserDetails implements UserDetails {
    //用户密码
    private String password;
    //用户名
    private String username;
    //用户角色信息
    private Collection<? extends GrantedAuthority> authorities;
    //启用
    private boolean enable;
    //认证未过期
    private boolean credentialsNonExpired;
    //账号未锁定
    private boolean accountNonExpired;
    //账号未锁定
    private boolean accountNonLocked;
    
   
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return this.accountNonExpired;
    }

    @Override
    public boolean isAccountNonLocked() {
        return this.accountNonLocked;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return this.credentialsNonExpired;
    }

    @Override
    public boolean isEnabled() {
        return this.enable;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
        this.authorities = authorities;
    }

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }

    public void setCredentialsNonExpired(boolean credentialsNonExpired) {
        this.credentialsNonExpired = credentialsNonExpired;
    }

    public void setAccountNonExpired(boolean accountNonExpired) {
        this.accountNonExpired = accountNonExpired;
    }

    public void setAccountNonLocked(boolean accountNonLocked) {
        this.accountNonLocked = accountNonLocked;
    }
}

安全配置(WebSecurityConfigurerAdapter)

因使用密码加密类,加密了密码,需要在配置中配置密码类。

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    //设置密码加密类
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

资源认证

资源认证,一般是基于URL与角色的认证。
需要自己定义

安全数据元(FilterInvocationSecurityMetadataSource)

通过数据库定义,URL和角色的授权关系。在将数据加入的缓存中已减少多次读取的问题。

设计的时候:

  1. 如果只是需要登录即可访问的资源,可以设计一个角色,在用户注册时候就授予这个角色。
  2. 如果需要指定角色,则需要URL和角色一一对应。
/**
 * 访问决策需要访问的资源
 */

public class CustomerFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    protected final Log logger = LogFactory.getLog(getClass());

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    public CustomerFilterInvocationSecurityMetadataSource(){

    }

    /**
     * 获取所有资源
     */
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<ConfigAttribute> allAttributes = new HashSet<>();
        logger.info("getAllConfigAttributes");

        return allAttributes;
    }

    /**
     * 根据请求,查找到匹配的资源
     */
    public Collection<ConfigAttribute> getAttributes(Object object) {
        logger.info("getAttributes");
        String url = ((FilterInvocation) object).getRequestUrl();
        int index = url.indexOf("?");
        if(index != -1){
            url = url.substring(0,index);
        }
        Collection<ConfigAttribute> collection = getRoleByUrl(url);
        //如果为空,则不进行校验
        if(collection.isEmpty()){

        }
        return collection;
    }

    /**
     * 获取请求路径的角色
     *
     */
    public Collection<ConfigAttribute> getRoleByUrl(String url) {
        //收集 匹配到路径的角色
        Collection<ConfigAttribute> collection = new HashSet<>();
        //获取路径和角色的资源,一般放在缓存中
       Map<String,Collection<ConfigAttribute>> map = new HashMap<>();
       Iterator<String> iterator = map.keySet().iterator();
       //这个角色是方便测试加入的,
       collection.add(new SecurityConfig("ADMIN"));
       while (iterator.hasNext()){
           String matchUrl = iterator.next();
           if(this.antPathMatcher.match(matchUrl,url)){
              Collection<ConfigAttribute> matchCollection = map.get(matchUrl);
              collection.addAll(matchCollection);
           }
       }
       return collection;
    }
    /**
     * 是否支持
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

访问决策管理

在获取URL对应的角色时,会将用户的角色和获取的角色进行比较,查看用户是否有权限访问。

/**
 * 访问决策管理
 */

public class CustomerAccessDecisionManager implements AccessDecisionManager {
    protected final Log logger = LogFactory.getLog(getClass());
    //一般进行角色校验

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        Iterator<ConfigAttribute> iterator = configAttributes.iterator();
        logger.info("decide");
        while (iterator.hasNext()){
            ConfigAttribute attribute = iterator.next();
            for(GrantedAuthority ga : authentication.getAuthorities()){
                if(attribute.getAttribute().equals(ga.getAuthority())){
                    return;
                }
            }

        }
        //返回访问拒绝信息
       throw new AccessDeniedException("Access reject!");
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}

安全拦截器(FilterSecurityInterceptor)

需要继承FilterSecurityInterceptor类,在这里设置安全元数据、访问决策管理。如果不需要的访问,可以通过重写进行覆盖父类的方法。

@Component
public class CustomerFilterSecurityInterceptor extends FilterSecurityInterceptor {

	//初始化方法,加载访问决策管理,和安全元数据。
    @PostConstruct
    public void init(){
        logger.info("init info");
        super.setSecurityMetadataSource(new CustomerFilterInvocationSecurityMetadataSource());
        super.setAccessDecisionManager(new CustomerAccessDecisionManager());
    }

    /**
     * 这一步可以不重写,使用系统自带的方法,如果不需要或是没有配置那些功能,则可以重写为自己想要的功能
     */
    @Override
    public void invoke(FilterInvocation fi) throws IOException, ServletException {
        logger.info("invoke");
        InterceptorStatusToken token = beforeInvocation(fi);
        try {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        }
        finally {
            super.finallyInvocation(token);
        }
        super.afterInvocation(token, null);
    }
}

安全配置(WebSecurityConfigurerAdapter)

在用户认证,安全配置类中加入,安全拦截器功能

/**
 * 配置类
 */
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    protected final Log logger = LogFactory.getLog(getClass());
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Override
    public void configure(WebSecurity web) throws Exception {
        logger.info("configure(WebSecurity web)");
        web.securityInterceptor(new CustomerFilterSecurityInterceptor());
    }
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 10:59:34  更:2022-09-13 11:00:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 12:06:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码