SpringBoot安全管理(一)

文章目录[隐藏]

SpringSecurity

Spring Security的安全管理有两个重要概念,分别是Authentication(认证)和Authorization(授权)

基本环境

创建一个springboot项目,导入相关依赖。在templates中引入相关资源,如下:

controller层

@GetMapping("/detail/{type}/{path}")
public String toDetail(@PathVariable("type") String type, @PathVariable("path") String path) {
    return "detail/" + type + "/" + path;
}

定义了跳转至详情页的方法

开启安全管理

只需引入依赖即可

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

一旦引入,即会生效

运行测试

启动项目,会产生一个随机的密码,用来登陆

此时访问http://localhost:8080,会自动重定向到http://localhost:8080/login,要求登陆

这时采用默认用户名user以及随机生成的密码登陆后,才可进行访问

自定义用户认证

通过自定义WebSecurityConfigurerAdapter类型的Bean组件,并重写configure(AuthenticationManagerBuilder auth)方法,实现自定义用户认证

内存认证

@EnableWebSecurity
/*
@EnableWebSecurity等同于
    @EnableGlobalAuthentication
    @Import(WebSecurityConfiguration.class)
    @Configuration同时使用
@EnableGlobalAuthentication:开启自定义的全局认证
@Import(WebSecurityConfiguration.class):进行自动化配置
@Configuration:将当前类作为配置类
 */
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //用户身份认证自定义配置
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //  密码需要设置编码器
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        // 1、使用内存用户信息,作为测试使用
        auth.inMemoryAuthentication().passwordEncoder(encoder)
                .withUser("shitou").password(encoder.encode("123456")).roles("common")
                .and()
                .withUser("李四").password(encoder.encode("123456")).roles("vip");
        /*
        自定义用户认证,必须设置密码编码器保护,推荐BCryptPasswordEncoder
        自定义用户认证时,可以自定义用户角色roles,也可以自定义用户权限authorities
        在自定义时,可以为同一个用户指定多个角色或者权限
         */
}

运行测试此时不会自动生成密码,使用自定义的配置进行登录即可

JDBC身份认证

数据库表结构

t_customer

t_authority

t_customer_authority

导入依赖,并在yml文件中进行数据库相关配置

<!-- JDBC数据库连接启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- MySQL数据连接驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

重写configure(AuthenticationManagerBuilder auth)方法方法

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;

    //用户身份认证自定义配置
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //  密码需要设置编码器
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        //使用JDBC进行身份认证
        String userSQL ="select username,password,valid from t_customer " +
                "where username = ?";
        String authoritySQL="select c.username,a.authority from t_customer c,t_authority a,"+
                "t_customer_authority ca where ca.customer_id=c.id " +
                "and ca.authority_id=a.id and c.username =?";
        auth.jdbcAuthentication().passwordEncoder(encoder)
                .dataSource(dataSource)
                .usersByUsernameQuery(userSQL)
                .authoritiesByUsernameQuery(authoritySQL);
        /*
        自定义用户查询的SQL语句时,必须返回username、password、valid三个字段信息
        自定义其权限查询SQL语句时,必须返回username、authority两个字段信息
        否则会报异常
         */
    }
}

此时再次进行测试,需要输入数据库中保存的用户名与密码即可

使用Service进行身份认证

在service层,有如下服务

@Service
public class CustomerService {
    @Autowired
    private CustomerRepository customerRepository;
    @Autowired
    private AuthorityRepository authorityRepository;
    @Autowired
    private RedisTemplate redisTemplate;

    // 业务控制:使用唯一用户名查询用户信息
    public Customer getCustomer(String username) {
        Customer customer = null;
        Object o = redisTemplate.opsForValue().get("customer_" + username);
        if (o != null) {
            customer = (Customer) o;
        } else {
            customer = customerRepository.findByUsername(username);
            if (customer != null) {
                redisTemplate.opsForValue().set("customer_" + username, customer);
            }
        }
        return customer;
    }

    // 业务控制:使用唯一用户名查询用户权限
    public List<Authority> getCustomerAuthority(String username) {
        List<Authority> authorities = null;
        Object o = redisTemplate.opsForValue().get("authorities_" + username);
        if (o != null) {
            authorities = (List<Authority>) o;
        } else {
            authorities = authorityRepository.findAuthoritiesByUsername(username);
            if (authorities.size() > 0) {
                redisTemplate.opsForValue().set("authorities_" + username, authorities);
            }
        }
        return authorities;
    }
}

其中结合了Redis缓存,另:AuthorityRepository和CustomerRepository如下

public interface AuthorityRepository extends JpaRepository<Authority,Integer> {
    @Query(value = "select a.* from t_customer c,t_authority a,t_customer_authority ca where ca.customer_id=c.id and ca.authority_id=a.id and c.username =?1",nativeQuery = true)
    public List<Authority> findAuthoritiesByUsername(String username);
}
public interface CustomerRepository extends JpaRepository<Customer,Integer> {
    Customer findByUsername(String username);
}

自定义UserDetailsService,用于封装认证用户信息

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private CustomerService customerService;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // 通过业务方法获取用户及权限信息
        Customer customer = customerService.getCustomer(s);
        List<Authority> authorities = customerService.getCustomerAuthority(s);
        // 对用户权限进行封装
        List<SimpleGrantedAuthority> list = authorities.stream().map(authority -> new SimpleGrantedAuthority(authority.getAuthority())).collect(Collectors.toList());
        // 返回封装的UserDetails用户详情类
        if (customer != null) {
            UserDetails userDetails = new User(customer.getUsername(), customer.getPassword(), list);
            return userDetails;
        } else {
            // 如果查询的用户不存在(用户名不存在),必须抛出此异常
            throw new UsernameNotFoundException("当前用户不存在!");
        }
    }
}

最后重写configure(AuthenticationManagerBuilder auth)方法即可

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    //用户身份认证自定义配置
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //  密码需要设置编码器
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        //使用UserDetailsService进行身份认证
        auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
    }
}

运行测试,效果与上面相同

源码下载

此节源码与下一节整合在一起,请前往下一节处下载


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot提供了强大的安全管理功能,可以方便地集成到应用程序中。以下是关于Spring Boot安全管理的几个关键点: 1. 身份验证和授权:Spring Security是Spring Boot内置的安全框架,它提供了身份验证和授权的功能。身份验证用于确认用户身份,授权则用于确定用户对特定资源的访问权限。Spring Security提供了多种身份验证方式,如基于用户名和密码的认证,OAuth2.0授权等。 2. 配置安全属性:Spring Boot提供了易于使用的安全属性配置,可以通过application.properties或application.yml文件进行配置。例如,可以设置是否启用安全功能,设置信任的SSL证书,配置登录页面等。 3. 跨域请求保护:Spring Boot支持跨域请求保护,可以防止跨域请求被攻击。通过配置CORS过滤器,可以允许特定的域名进行跨域请求。 4. 安全性日志:Spring Boot提供了安全性日志功能,可以记录用户请求、认证失败、授权失败等信息。这有助于跟踪安全事件,并进行安全审计。 5. 安全性审计:Spring Boot支持安全性审计功能,可以对用户请求、认证信息、授权信息等进行审计。这有助于发现潜在的安全问题,并进行安全整改。 6. 安全性加密:Spring Boot提供了安全性加密功能,可以对敏感数据进行加密和解密。通过使用Spring Security提供的加密工具类和方法,可以方便地进行数据加密和解密操作。 总之,Spring Boot提供了丰富的安全管理功能,可以帮助开发者构建安全可靠的应用程序。通过配置和使用Spring Security,可以轻松地实现身份验证、授权、日志、审计和加密等功能,提高应用程序的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值