Java技术债务Java技术债务

  •  首页
  •  分类
  •  归档
  •  标签
  • 博客日志
  • 资源分享
  •  友链
  •  关于本站
注册
登录

Spring Security认证和授权(二)

Java,Spring

文章目录

  • 1.
  • 默认数据库认证和授权
  • 2.
  • 自定义数据库模型的认证与授权

1. 默认数据库认证和授权

1.1 资源准备

首先准备三个不同权限的接口

@GetMapping("/admin/test")
@ResponseBody
public String adminTest() {
    return "admin test";
}

@GetMapping("/user/test")
@ResponseBody
public String userTest() {
    return "user test";
}

@GetMapping("/web/test")
@ResponseBody
public String webTest() {
    return "web test";
}

假设在/admin/test/下的内容是系统后台管理相关的 API,在/web/test下的内容是面向客户端公开访 问的API,在/user/test/下的内容是用户操作自身数据相关的API;显然,/admin/test必须拥有管理员权限才能进行操作,而/user/test必须在用户登录后才能进行操作。

1.2 资源授权的配置

/**
 * @author: Java技术债务
 * @Date: 2021/6/5 18:45
 * Describe: SpringSecurity配置
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/test/**").hasRole("admin")
                .antMatchers("/user/test/**").hasRole("user")
                .antMatchers("/web/test/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin();

    }
}

antMatchers()是一个采用ANT模式的URL匹配器。ANT模式使用?匹配任意单个字符,使用* 匹配0或任意数量的字符,使用匹配0或者更多的目录。antMatchers("/admin/test/")相当于匹配 了/admin/test/下的所有API。此处我们指定当其必须为admin角色时才能访问,/user/test/与之同 理。/web/test/下的API会调用permitAll()公开其权限。

重启服务测试

Spring Security认证和授权(二) - Java技术债务

Spring Security认证和授权(二) - Java技术债务

页面显示403错误,表示该用户授权失败(401代表该用户认证失败)。也就是说,本次访问已经通过了认证环节,只是在授权的时候被驳回了。认证环节是没有问题的,因为Spring Security默认的用 户角色正是user。 HTTP状态码(HTTP Status Code)是由RFC 2616定义的一种用来表示一个HTTP请求响应状态的 规范,由3位数字组成。通常用2XX表示本次操作成功,用4XX表示是客户端导致的失败,用5XX表示 是服务器引起的错误。

访问/web/test/却成功了,因为/web/test/是允许所有角色访问。

1.3 基于内存的多用户支持

到目前为止,我们仍然只有一个可登录的用户,怎样引入多用户呢?非常简单,我们只需实现一 个自定义的UserDetails Service即可。

package com.demo.springSecurityFirstDemo.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/**
 * @author: Java技术债务
 * @Date: 2021/6/5 18:45
 * Describe: SpringSecurity配置
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/test/**").hasRole("ADMIN")
                .antMatchers("/user/test/**").hasRole("USER")
                .antMatchers("/web/test/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin();

    }

    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
        userDetailsManager.createUser(User.withUsername("user").password("1").roles("USER").build());
        userDetailsManager.createUser(User.withUsername("admin").password("1").roles("USER", "ADMIN").build());

        return userDetailsManager;
    }
}

为其添加一个@bean注解,便可被 Spring Security 发现并使用。Spring Security支持各种来源的用户数据,包括内存、数据库、LDAP等。它们被抽象为一个UserDetailsService接口,任何实现了 UserDetailsService 接口的对象都可以作为认证数据源。在这种设计模式下,Spring Security 显得尤为灵活。 IMemory UserDetailsManager是 UserDetails Service接口中的一个实现类,它将用户数据源寄存在内存里,在一些不需要引入数据库这种重数据源的系统中很有帮助。

1.4 认证和授权

除了IMemoryUserDetailsManagsr, Spring Security还提供另一个UserDetailsService实现类: JdbcUserDetailsManager。

JdbcUserDetailsManager帮助我们以JDBC的方式对接数据库和Spring Security,它设定了一个默认的数据库模型,只要遵从这个模型,在简便性上,JdbcUserDetailsManager甚至可以媲美InMemory UserDetailsManager。

1.4.1 数据库准备

数据库方面的不需要我多说什么了吧。

唯一要说的就是创建的表

Spring Security认证和授权(二) - Java技术债务

JdbcUserDetailsManager需要两个表,其中users表用来存放用户名、密码和是否可用三个信息, authorities表用来存放用户名及其权限的对应关系。将其复制到MySQL命令窗口执行时,会报错,因为该语句是用hsqldb创建的,而MySQL不支持 varchar_ignorecase这种类型。怎么办呢?很简单,将varchar_ignorecase改为MySQL支持的varchar即可。

1.4.2 编码

Spring Security认证和授权(二) - Java技术债务

JdbcUserDetailsManager与InMemoryUserDetailsManager在用法上没有太大区别,只是多了设置 DataSource 的环节。Spring Security 通过 DataSource 执行设定好的命令。

例如,此处的createUser函数 实际上就是执行了下面的SQL语句。

查看 JdbcUserDetailsManager 的源代码可以看到更多定义好的 SQL 语句,诸如deleteUserSql、 updateUserSql等,这些都是JdbcUserDetailsManager与数据库实际交互的形式。当然, JdbcUserDetailsManager 也允许我们在特殊情况下自定义这些 SQL语句,如有必要,调用对应的setXxxSql方法即可。

Spring Security认证和授权(二) - Java技术债务

当使用Spring Security默认数据库模型应对各种用户系统时,难免灵活性欠佳。尤其是在对现有的 系统做Spring Security嵌入时,原本的用户数据已经固定,为了适配Spring Security而在数据库层面进行 修改显然得不偿失。强大而灵活的Spring Security对这方面进行了改进。

2. 自定义数据库模型的认证与授权

2.1 实现UserDetails

之前使用了InMemoryUserDetailsManager 和 JdbcUserDetailsManager 两个UserDetailsService 实现类。生效方式也很简单,只需加入 Spring 的 IoC 容器,就会被 Spring Security自动发现并使用。自定义数据库结构实际上也仅需实现一个自定义的UserDetails Service。

UserDetailsService仅定义了一个loadUserBy Username方法,用于获取一个UserDetails对象。UserDetails对象包含了一系列在验证时会用到的信息,包括用户名、密码、权限以及其他信息,Spring Security会根据这些信息判定验证是否成功。

Spring Security认证和授权(二) - Java技术债务

也就是说,不管数据库结构如何变化,只要能构造一个UserDetails即可,下面就来实现这个过 程。

2.2 数据库以及表准备

SecurityUser.java

package com.demo.springSecurityFirstDemo.security;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;

/**
 * @Author Java技术债务
 * @Date 2022-03-26 19:12:56
 * @Desc *
 */
public class SecurityUser implements UserDetails {
    private Integer id;

    private String username;

    private String password;

    private boolean enable;

    private List<GrantedAuthority> authorityList;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

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

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

    public boolean isEnable() {
        return enable;
    }

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

    public List<GrantedAuthority> getAuthorityList() {
        return authorityList;
    }

    public void setAuthorityList(List<GrantedAuthority> authorityList) {
        this.authorityList = authorityList;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorityList;
    }

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

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

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

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

实现UserDetails定义的几个方法: ◎ isAccountNonExpired、isAccountNonLocked 和 isCredentialsNonExpired 暂且用不到,统一返回 true,否则Spring Security会认为账号异常。 ◎ isEnabled对应enable字段,将其代入即可。 ◎ getAuthorities方法本身对应的是roles字段,但由于结构不一致,所以此处新建一个,并在后续 进行填充。

2.3 实现UserDetailsService

package com.demo.springSecurityFirstDemo.security;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.demo.springSecurityFirstDemo.model.UserModel;
import com.demo.springSecurityFirstDemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author Java技术债务
 * @Date 2022-03-22 22:19:51
 * @Desc *
 *
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;
    /**
     * Security的登录,User赋予权限
     *
     * @param userName
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        System.out.println(userName);
        QueryWrapper<UserModel> qw = new QueryWrapper<>();
        qw.eq("user_name", userName);
        UserModel userModel = userService.getOne(qw);
        if (userModel == null) {
            throw new UsernameNotFoundException("user not exist!");
        }
        SecurityUser securityUser = new SecurityUser();
        securityUser.setId(userModel.getId());
        securityUser.setUsername(userModel.getUserName());
        securityUser.setPassword(userModel.getPassword());
        securityUser.setAuthorityList(AuthorityUtils.commaSeparatedStringToAuthorityList(userModel.getRoles()));
        securityUser.setEnable(userModel.getIsDeleted() == 0);

        return securityUser;
    }
}

其中AuthorityUtils.commaSeparatedStringToAuthorityList(userModel.getRoles()) 是将逗号拼接的权限字符串,比如:ROLE_USER,ROLE_ADMIN。

SimpleGrantedAuthority是GrantedAuthority的一个实现类。Spring Security的权限几乎是用 SimpleGrantedAuthority生成的,只要注意每种角色对应一个GrantedAuthority即可。另外,一定要在自 己的UserDetailsService实现类上加入@Service注解,以便被Spring Security自动发现。

[WebSecurityConfig.java](http://WebSecurityConfig.java) 完整代码

package com.demo.springSecurityFirstDemo.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.provisioning.JdbcUserDetailsManager;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

/**
 * @author: Java技术债务
 * @Date: 2021/6/5 18:45
 * Describe: SpringSecurity配置
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/test/**").hasRole("ADMIN")
                .antMatchers("/user/test/**").hasRole("USER")
                .antMatchers("/web/test/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin();

    }
}

2.4 启动程序测试

登录数据库保存的账号密码用户名:user密码:1权限role_user

返回配置的成功页面

Spring Security认证和授权(二) - Java技术债务

然后依次访问不同权限的接口

  • 访问/admin/test

Spring Security认证和授权(二) - Java技术债务

  • 访问/user/test

Spring Security认证和授权(二) - Java技术债务

登录数据库保存的账号密码用户名:admin密码:1权限为role_admin和role_user

访问/admin/test和/user/test/正常。

如果登录不存在的用户测试结果如图。

Spring Security认证和授权(二) - Java技术债务

1. 默认数据库认证和授权

1.1 资源准备

首先准备三个不同权限的接口

@GetMapping("/admin/test")
@ResponseBody
public String adminTest() {
    return "admin test";
}

@GetMapping("/user/test")
@ResponseBody
public String userTest() {
    return "user test";
}

@GetMapping("/web/test")
@ResponseBody
public String webTest() {
    return "web test";
}

假设在/admin/test/下的内容是系统后台管理相关的 API,在/web/test下的内容是面向客户端公开访 问的API,在/user/test/下的内容是用户操作自身数据相关的API;显然,/admin/test必须拥有管理员权限才能进行操作,而/user/test必须在用户登录后才能进行操作。

1.2 资源授权的配置

/**
 * @author: Java技术债务
 * @Date: 2021/6/5 18:45
 * Describe: SpringSecurity配置
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/test/**").hasRole("admin")
                .antMatchers("/user/test/**").hasRole("user")
                .antMatchers("/web/test/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin();

    }
}

antMatchers()是一个采用ANT模式的URL匹配器。ANT模式使用?匹配任意单个字符,使用* 匹配0或任意数量的字符,使用匹配0或者更多的目录。antMatchers("/admin/test/")相当于匹配 了/admin/test/下的所有API。此处我们指定当其必须为admin角色时才能访问,/user/test/与之同 理。/web/test/下的API会调用permitAll()公开其权限。

重启服务测试

Spring Security认证和授权(二) - Java技术债务

Spring Security认证和授权(二) - Java技术债务

页面显示403错误,表示该用户授权失败(401代表该用户认证失败)。也就是说,本次访问已经通过了认证环节,只是在授权的时候被驳回了。认证环节是没有问题的,因为Spring Security默认的用 户角色正是user。 HTTP状态码(HTTP Status Code)是由RFC 2616定义的一种用来表示一个HTTP请求响应状态的 规范,由3位数字组成。通常用2XX表示本次操作成功,用4XX表示是客户端导致的失败,用5XX表示 是服务器引起的错误。

访问/web/test/却成功了,因为/web/test/是允许所有角色访问。

1.3 基于内存的多用户支持

到目前为止,我们仍然只有一个可登录的用户,怎样引入多用户呢?非常简单,我们只需实现一 个自定义的UserDetails Service即可。

package com.demo.springSecurityFirstDemo.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/**
 * @author: Java技术债务
 * @Date: 2021/6/5 18:45
 * Describe: SpringSecurity配置
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/test/**").hasRole("ADMIN")
                .antMatchers("/user/test/**").hasRole("USER")
                .antMatchers("/web/test/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin();

    }

    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
        userDetailsManager.createUser(User.withUsername("user").password("1").roles("USER").build());
        userDetailsManager.createUser(User.withUsername("admin").password("1").roles("USER", "ADMIN").build());

        return userDetailsManager;
    }
}

为其添加一个@bean注解,便可被 Spring Security 发现并使用。Spring Security支持各种来源的用户数据,包括内存、数据库、LDAP等。它们被抽象为一个UserDetailsService接口,任何实现了 UserDetailsService 接口的对象都可以作为认证数据源。在这种设计模式下,Spring Security 显得尤为灵活。 IMemory UserDetailsManager是 UserDetails Service接口中的一个实现类,它将用户数据源寄存在内存里,在一些不需要引入数据库这种重数据源的系统中很有帮助。

1.4 认证和授权

除了IMemoryUserDetailsManagsr, Spring Security还提供另一个UserDetailsService实现类: JdbcUserDetailsManager。

JdbcUserDetailsManager帮助我们以JDBC的方式对接数据库和Spring Security,它设定了一个默认的数据库模型,只要遵从这个模型,在简便性上,JdbcUserDetailsManager甚至可以媲美InMemory UserDetailsManager。

1.4.1 数据库准备

数据库方面的不需要我多说什么了吧。

唯一要说的就是创建的表

Spring Security认证和授权(二) - Java技术债务

JdbcUserDetailsManager需要两个表,其中users表用来存放用户名、密码和是否可用三个信息, authorities表用来存放用户名及其权限的对应关系。将其复制到MySQL命令窗口执行时,会报错,因为该语句是用hsqldb创建的,而MySQL不支持 varchar_ignorecase这种类型。怎么办呢?很简单,将varchar_ignorecase改为MySQL支持的varchar即可。

1.4.2 编码

Spring Security认证和授权(二) - Java技术债务

JdbcUserDetailsManager与InMemoryUserDetailsManager在用法上没有太大区别,只是多了设置 DataSource 的环节。Spring Security 通过 DataSource 执行设定好的命令。

例如,此处的createUser函数 实际上就是执行了下面的SQL语句。

查看 JdbcUserDetailsManager 的源代码可以看到更多定义好的 SQL 语句,诸如deleteUserSql、 updateUserSql等,这些都是JdbcUserDetailsManager与数据库实际交互的形式。当然, JdbcUserDetailsManager 也允许我们在特殊情况下自定义这些 SQL语句,如有必要,调用对应的setXxxSql方法即可。

Spring Security认证和授权(二) - Java技术债务

当使用Spring Security默认数据库模型应对各种用户系统时,难免灵活性欠佳。尤其是在对现有的 系统做Spring Security嵌入时,原本的用户数据已经固定,为了适配Spring Security而在数据库层面进行 修改显然得不偿失。强大而灵活的Spring Security对这方面进行了改进。

2. 自定义数据库模型的认证与授权

2.1 实现UserDetails

之前使用了InMemoryUserDetailsManager 和 JdbcUserDetailsManager 两个UserDetailsService 实现类。生效方式也很简单,只需加入 Spring 的 IoC 容器,就会被 Spring Security自动发现并使用。自定义数据库结构实际上也仅需实现一个自定义的UserDetails Service。

UserDetailsService仅定义了一个loadUserBy Username方法,用于获取一个UserDetails对象。UserDetails对象包含了一系列在验证时会用到的信息,包括用户名、密码、权限以及其他信息,Spring Security会根据这些信息判定验证是否成功。

Spring Security认证和授权(二) - Java技术债务

也就是说,不管数据库结构如何变化,只要能构造一个UserDetails即可,下面就来实现这个过 程。

2.2 数据库以及表准备

SecurityUser.java

package com.demo.springSecurityFirstDemo.security;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;

/**
 * @Author Java技术债务
 * @Date 2022-03-26 19:12:56
 * @Desc *
 */
public class SecurityUser implements UserDetails {
    private Integer id;

    private String username;

    private String password;

    private boolean enable;

    private List<GrantedAuthority> authorityList;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

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

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

    public boolean isEnable() {
        return enable;
    }

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

    public List<GrantedAuthority> getAuthorityList() {
        return authorityList;
    }

    public void setAuthorityList(List<GrantedAuthority> authorityList) {
        this.authorityList = authorityList;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorityList;
    }

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

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

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

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

实现UserDetails定义的几个方法: ◎ isAccountNonExpired、isAccountNonLocked 和 isCredentialsNonExpired 暂且用不到,统一返回 true,否则Spring Security会认为账号异常。 ◎ isEnabled对应enable字段,将其代入即可。 ◎ getAuthorities方法本身对应的是roles字段,但由于结构不一致,所以此处新建一个,并在后续 进行填充。

2.3 实现UserDetailsService

package com.demo.springSecurityFirstDemo.security;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.demo.springSecurityFirstDemo.model.UserModel;
import com.demo.springSecurityFirstDemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author Java技术债务
 * @Date 2022-03-22 22:19:51
 * @Desc *
 *
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;
    /**
     * Security的登录,User赋予权限
     *
     * @param userName
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        System.out.println(userName);
        QueryWrapper<UserModel> qw = new QueryWrapper<>();
        qw.eq("user_name", userName);
        UserModel userModel = userService.getOne(qw);
        if (userModel == null) {
            throw new UsernameNotFoundException("user not exist!");
        }
        SecurityUser securityUser = new SecurityUser();
        securityUser.setId(userModel.getId());
        securityUser.setUsername(userModel.getUserName());
        securityUser.setPassword(userModel.getPassword());
        securityUser.setAuthorityList(AuthorityUtils.commaSeparatedStringToAuthorityList(userModel.getRoles()));
        securityUser.setEnable(userModel.getIsDeleted() == 0);

        return securityUser;
    }
}

其中AuthorityUtils.commaSeparatedStringToAuthorityList(userModel.getRoles()) 是将逗号拼接的权限字符串,比如:ROLE_USER,ROLE_ADMIN。

SimpleGrantedAuthority是GrantedAuthority的一个实现类。Spring Security的权限几乎是用 SimpleGrantedAuthority生成的,只要注意每种角色对应一个GrantedAuthority即可。另外,一定要在自 己的UserDetailsService实现类上加入@Service注解,以便被Spring Security自动发现。

[WebSecurityConfig.java](http://WebSecurityConfig.java) 完整代码

package com.demo.springSecurityFirstDemo.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.provisioning.JdbcUserDetailsManager;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

/**
 * @author: Java技术债务
 * @Date: 2021/6/5 18:45
 * Describe: SpringSecurity配置
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/test/**").hasRole("ADMIN")
                .antMatchers("/user/test/**").hasRole("USER")
                .antMatchers("/web/test/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin();

    }
}

2.4 启动程序测试

登录数据库保存的账号密码用户名:user密码:1权限role_user

返回配置的成功页面

Spring Security认证和授权(二) - Java技术债务

然后依次访问不同权限的接口

  • 访问/admin/test

Spring Security认证和授权(二) - Java技术债务

  • 访问/user/test

Spring Security认证和授权(二) - Java技术债务

登录数据库保存的账号密码用户名:admin密码:1权限为role_admin和role_user

访问/admin/test和/user/test/正常。

如果登录不存在的用户测试结果如图。

Spring Security认证和授权(二) - Java技术债务

完
  • 本文作者:Java技术债务
  • 原文链接: https://cuizb.top/myblog/article/1648393808
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY 3.0 CN协议进行许可。转载请署名作者且注明文章出处。
阅读全文
Java技术债务

Java技术债务

Java技术债务
Java技术债务
热门文章
  1. ClickHouse使用过程中的一些查询优化(六)2003
  2. MySQL数据库被攻击,被删库勒索,逼迫我使出洪荒之力进行恢复数据764
  3. MySQL主从同步原理458
  4. 线程池的理解以及使用414
  5. Spring Cloud Gateway整合nacos实战(三)409
分类
  • Java
    30篇
  • 设计模式
    27篇
  • 数据库
    20篇
  • Spring
    18篇
  • MySQL
    13篇
  • ClickHouse
    11篇
  • Kubernetes
    10篇
  • Redis
    9篇
  • Docker
    8篇
  • SpringBoot
    7篇
  • JVM
    6篇
  • Linux
    5篇
  • Spring Cloud
    5篇
  • 多线程
    5篇
  • Netty
    4篇
  • Kafka
    4篇
  • 面经
    4篇
  • Nginx
    3篇
  • JUC
    3篇
  • 随笔
    2篇
  • 分布式
    1篇
  • MyBatis
    1篇
  • 报错合集
    1篇
  • 生活记录
    1篇
  • 源码
    1篇
  • 性能优化
    1篇

最新评论

  • MySQL数据库被攻击,被删库勒索,逼迫我使出洪荒之力进行恢复数据2022-05-06
    Java技术债务:@capture 一起探讨学习,服务器被黑很正常,及时做好备份以及做好防护
  • MySQL数据库被攻击,被删库勒索,逼迫我使出洪荒之力进行恢复数据2022-04-13
    capture:我的刚上线两天,网站里就两篇文章也被攻击了,纳闷
  • Java常用集合List、Map、Set介绍以及一些面试问题2022-01-18
    Java技术债务:HashSet和TreeSet 相同点:数据不能重复 不同点: 1、底层存储结构不同; HashSet底层使用HashMap哈希表存储 TreeSet底层使用TreeMap树结构存储 2、唯一性方式不同 HashSet底层使用hashcode()和equal()方法判断 TreeSet底层使用Comparable接口的compareTo判断的 3、HashSet无序,TreeSet有序
  • undefined2021-12-14
    Java技术债务:如果不指定线程池,CompletableFuture会默认使用ForkJoin线程池,如果同一时间出现大量请求的话,会出现线程等待问题,建议使用自定义线程池。。。
  • undefined2021-12-02
    you:很好,对于小白相当不错了,谢谢
  • CSDN
  • 博客园
  • 程序猿DD
  • 纯洁的微笑
  • spring4all
  • 廖雪峰的官方网站
  • 猿天地
  • 泥瓦匠BYSocket
  • crossoverJie
  • 张先森个人博客
  • 越加网

© 2021-2022 Java技术债务 - Java技术债务 版权所有
总访问量 0 次 您是本文第 0 位童鞋
豫ICP备2021034516号
Java技术债务 豫公网安备 51011402000164号

微信公众号

Java技术债务
Java技术债务

专注于Spring,SpringBoot等后端技术探索

以及MySql数据库开发和Netty等后端流行框架学习

日志
分类
标签
RSS

有不足之处也希望各位前辈指出