Springboot 集成Spring Security教程 (三)

这一篇将进行 Security 从数据库读取用户信息及权限

数据库采用 Mysql, ROM 采用 JPA

首先进行 JPA 的配置, 在 application.properties 中添加(JPA 的使用将在后续文章中做记录)

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
# jpa
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

一. 创建 SysUser 和 SysRole 及对应的数据库操作类(JPA)

这两个实体类使用的是 JPA 自动建表, dao 层继承 JpaRepository

SysUser类

Security 中的权限认证需要实现 UserDetails 接口 , 并复写其方法. getAuthorities() 方法返回的是权限点

package com.izuul.springsecurity.entity;

import lombok.Data;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;

@Data
@Entity(name = "SYS_USER")
public class SysUser implements UserDetails, Serializable {

    private static final long serialVersionUID = -2476551158093701699L;

    @Id
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @GeneratedValue(generator = "system-uuid")
    @Column(name = "ID")
    private String id;

    @Column(name = "USERNAME")
    private String username;

    @Column(name = "PASSWORD")
    private String password;

    @ManyToMany
    @JoinTable(name = "USER_ROLE", joinColumns = @JoinColumn(name = "USER_ID", referencedColumnName = "ID"),
            inverseJoinColumns = @JoinColumn(name = "ROLE_ID", referencedColumnName = "ID"))
    private List<SysRole> sysRoles;

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

    @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 true;
    }
}

SysRole 类

实现 GrantedAuthority 接口, 复写 getAuthority()方法

package com.izuul.springsecurity.entity;

import lombok.Data;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.security.core.GrantedAuthority;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.io.Serializable;

@Data
@Entity(name = "SYS_ROLE")
public class SysRole implements GrantedAuthority, Serializable {

    private static final long serialVersionUID = -1834111111498772935L;

    @Id
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @GeneratedValue(generator = "system-uuid")
    @Column(name = "ID")
    private String id;

    @Column(name = "NAME")
    private String name;

    @Override
    public String getAuthority() {
        return name;
    }
}

SysUserRepository

继承 JpaRepository, 写一个 findByUsername() 方法

package com.izuul.springsecurity.repository;

import com.izuul.springsecurity.entity.SysUser;
import org.springframework.data.jpa.repository.JpaRepository;

public interface SysUserRepository extends JpaRepository<SysUser, String> {

    SysUser findByUsername(String username);
}

SysRoleRepository
package com.izuul.springsecurity.repository;

import com.izuul.springsecurity.entity.SysRole;
import org.springframework.data.jpa.repository.JpaRepository;

public interface SysRoleRepository extends JpaRepository<SysRole, String> {
}

二. 创建 UserDetailsService 实现类

Security 从数据库读取用户认证信息需要对 SecurityConfig 配置类进行更改

SecurityConfig 中需要引用 UserDetailsService 的实现类, 我先创建这个实现类

  • 实现 UserDetailsService 接口 复写 loadUserByUsername(String username) 方法

  • 创建初始化用户的 init() 方法

  • 使用 PasswordEncoder 对密码进行加密

package com.izuul.springsecurity.service;

import com.izuul.springsecurity.entity.SysRole;
import com.izuul.springsecurity.entity.SysUser;
import com.izuul.springsecurity.repository.SysRoleRepository;
import com.izuul.springsecurity.repository.SysUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

@Service
public class SysUserService implements UserDetailsService {

    @Autowired
    private SysUserRepository sysUserRepository;

    @Autowired
    private SysRoleRepository sysRoleRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 初始化2个用户
     */
    @PostConstruct
    private void init() {
        if (sysUserRepository.findByUsername("admin") == null) {
            SysRole roleAdmin = new SysRole();
            roleAdmin.setName("ROLE_ADMIN");

            SysUser sysAdmin = new SysUser();
            sysAdmin.setUsername("admin");
            sysAdmin.setPassword(passwordEncoder.encode("123"));
            List<SysRole> sysRolesAdmin = new ArrayList<>();
            sysRolesAdmin.add(roleAdmin);
            sysAdmin.setSysRoles(sysRolesAdmin);

            sysRoleRepository.save(roleAdmin);
            sysUserRepository.save(sysAdmin);
        }

        if (sysUserRepository.findByUsername("user") == null) {
            SysRole roleUser = new SysRole();
            roleUser.setName("ROLE_USER");

            SysUser sysUser = new SysUser();
            sysUser.setUsername("user");
            sysUser.setPassword(passwordEncoder.encode("123"));
            List<SysRole> sysRolesUser = new ArrayList<>();
            sysRolesUser.add(roleUser);
            sysUser.setSysRoles(sysRolesUser);

            sysRoleRepository.save(roleUser);
            sysUserRepository.save(sysUser);

        }


    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return sysUserRepository.findByUsername(username);
    }


}

二. 复写 configure(AuthenticationManagerBuilder auth) 方法

将上篇中从内存都认证信息的配置注销, 并复写 configure(AuthenticationManagerBuilder auth) 方法

 		@Autowired
    private SysUserService sysUserService;
    
//    @Autowired
//    public void config(AuthenticationManagerBuilder auth) throws Exception {
//        auth.inMemoryAuthentication()
//                .passwordEncoder(passwordEncoder())
//                .withUser("izuul")
//                .password(passwordEncoder().encode("izuul"))
//                .roles("USER");
//    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(sysUserService);
    }

配置好config 并连接数据库后, 启动项目

启动后会自动建表并插入初始化数据, 创建了两个用户 admin 和 user,

admin 用户的权限点是 ADMIN, user 用户的是 USER, 上篇中configure 做的资源配置如下

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 根路径 "/" 允许全部访问请求
                .antMatchers("/").permitAll()
                // 路径 "/user/**" 只允许
                .antMatchers("/users/**").hasRole("USER")
                .and()
                .formLogin().loginPage("/login").failureUrl("/login-error")
                .and()
                .logout().logoutSuccessUrl("/logout-");
    }

所以当我们使用 user 用户登录的时候可以正常访问

而 admin 用户登录的时候会抛出异常说明权限不够, 在实际项目中需要进行异常处理, 本文就不做相关展示了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Security 是一个基于 Spring 的安全框架,提供了一组完整的安全性功能,包括身份验证、授权、防止 CSRF 攻击等等。Spring Boot 基于 Spring,自然也集成Spring Security。下面是 Spring Boot 集成 Spring Security 的步骤: 1. 在 pom.xml 中添加 Spring Security 的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2. 编写一个继承自 WebSecurityConfigurerAdapter 的配置类,并使用 @EnableWebSecurity 注解开启 Spring Security: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/", "/home").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user").password("password").roles("USER"); } } ``` 上面的代码中,我们配置了 Spring Security 的基本功能:对所有请求进行身份验证,允许访问首页和登录页面,使用 inMemoryAuthentication 来指定用户和密码。 3. 在 application.properties 或 application.yml 中配置登录页面的 URL: ```properties spring.security.login.form=/login ``` 4. 编写一个登录页面,例如一个 Thymeleaf 模板: ```html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <form th:action="@{/login}" method="post"> <div><label>Username: <input type="text" name="username"/></label></div> <div><label>Password: <input type="password" name="password"/></label></div> <div><input type="submit" value="Log in"/></div> </form> </body> </html> ``` 这样就完成了 Spring Boot 集成 Spring Security 的配置。当用户访问受保护的页面时,会被重定向到登录页面进行身份验证。如果用户输入的用户名和密码正确,就会跳转到原来请求的页面。如果不正确,就会显示错误信息。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值