222.Spring Boot+Spring Security:动态加载角色_Spring Boot+Spring S

说明

(1)JDK版本:1.8

(2)Spring Boot 2.0.6

(3)Spring Security 5.0.9

(4)Spring Data JPA 2.0.11.RELEASE

(5)hibernate5.2.17.Final

(6)MySQLDriver 5.1.47

(7)MySQL 8.0.12

 

需求缘起

       之前的版本的用户角色通过enum的方式硬编码了,实际场景中,我们会有一个角色表进行储存角色,如下图:

222.Spring Boot+Spring Security:动态加载角色_Spring Boot+Spring S_02

 

       那么怎么动态加载角色呢?

 

一、动态加载角色

1.1 定义角色实体类

       定义一个角色实体类Role:

package com.kfit.permission.bean;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Role {
    @Id @GeneratedValue
    private long rid;//主键.
    private String name;//角色名称.
    private String description;//角色描述.

    public Role() {
    }

    public Role(String name, String description) {
        this.name = name;
        this.description = description;
    }

    public long getRid() {
        return rid;
    }
    public void setRid(long rid) {
        this.rid = rid;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

}

 

1.2 角色持久化

       创建RoleRepository持久化操作:

 

package com.kfit.permission.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.kfit.permission.bean.Role;

public interface RoleRepository extends JpaRepository<Role,Long>{

}

 

1.3 修改UserInfo的用户角色

       这里用户和角色的关系是多对多的(一个用户可以拥有多个角色,一个角色可以被多个用户拥有),所以使用@ManyToMany注解它们之间的关系:

package com.kfit.permission.bean;

import java.util.List;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

@Entity
public class UserInfo {

    @Id @GeneratedValue
    private long uid;//主键.

    private String username;//用户名.
    private String password;//密码.

    //用户--角色:多对多的关系.
    @ManyToMany(fetch=FetchType.EAGER)//立即从数据库中进行加载数据;
    @JoinTable(name = "UserRole", joinColumns = { @JoinColumn(name = "uid") }, inverseJoinColumns ={@JoinColumn(name = "role_id") })
    private List<Role> roles;


    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    public long getUid() {
        return uid;
    }

    public void setUid(long uid) {
        this.uid = uid;
    }

    public String getUsername() {
        return username;
    }

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

    public String getPassword() {
        return password;
    }

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

       这样的话,就会自动创建一个关联表user_role:

222.Spring Boot+Spring Security:动态加载角色_Spring Boot+Spring S_03

1.4 修改CustomUserDetailService

CustomUserDetailService这里需要调整下角色的添加方式,如下代码:

package com.kfit.config;

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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.Component;

import com.kfit.permission.bean.Role;
import com.kfit.permission.bean.UserInfo;
import com.kfit.permission.service.UserInfoService;

@Component
public class CustomUserDetailService implements UserDetailsService{
    @Autowired
    private UserInfoService userInfoService;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("CustomUserDetailService.loadUserByUsername()");
        //通过username获取用户信息
        UserInfo userInfo = userInfoService.findByUsername(username);
        if(userInfo == null) {
            throw new UsernameNotFoundException("not found");
        }

        //定义权限列表.
        List<GrantedAuthority> authorities = new ArrayList<>();
        // 用户可以访问的资源名称(或者说用户所拥有的权限) 注意:必须"ROLE_"开头
        for(Role role:userInfo.getRoles()) {
            authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName()));
        }

        User userDetails = new User(userInfo.getUsername(),userInfo.getPassword(),authorities);
        return userDetails;
    }

}

 

1.5 修改DataInit

       最后我们需要修改下初始化数据的方法:

package com.kfit.permission.init;

import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import com.kfit.permission.bean.Role;
import com.kfit.permission.bean.UserInfo;
import com.kfit.permission.repository.RoleRepository;
import com.kfit.permission.repository.UserInfoRepository;

@Service
public class DataInit {

    @Autowired 
    private UserInfoRepository userInfoRepository;

    @Autowired 
    private PasswordEncoder passwordEncoder;

    @Autowired 
    private RoleRepository roleRepository;


    @PostConstruct
    public void dataInit() {

        List<Role> roles = new ArrayList<>();
        Role adminRole= new Role("admin","管理员");
        Role normalRole = new Role("normal","普通用户");
        roleRepository.save(adminRole);
        roleRepository.save(normalRole);

        roles.add(adminRole);
        roles.add(normalRole);

        UserInfo admin = new UserInfo();
        admin.setUsername("admin");
        admin.setPassword(passwordEncoder.encode("123"));
        admin.setRoles(roles);
        userInfoRepository.save(admin);


        roles = new ArrayList<>();
        roles.add(normalRole);

        UserInfo user = new UserInfo();
        user.setUsername("user");
        user.setPassword(passwordEncoder.encode("123"));
        user.setRoles(roles);
        userInfoRepository.save(user);
    }

}

 

1.6 运行测试

       运行成功的话,可以看到自动构建表:

222.Spring Boot+Spring Security:动态加载角色_Spring Boot+Spring S_04

 

 

role的数据:

222.Spring Boot+Spring Security:动态加载角色_Spring Boot+Spring S_05

 

 

user_info的数据:

222.Spring Boot+Spring Security:动态加载角色_Spring Boot+Spring S_06

 

 

user_role的数据:

222.Spring Boot+Spring Security:动态加载角色_Spring Boot+Spring S_07

 

       到这里已经支持角色动态从数据库中进行加载了,测试下admin和user吧。

历史文章

214. Spring Security:概述

215.Spring Boot+Spring Security:初体验

216.Spring Boot+Spring Security:基于内存的认证信息

217.Spring Boot+Spring Security:基于内存的角色授权

218.Spring Boot+Spring Security:基于内存数据库的身份认证和角色授权

219.Spring Boot+Spring Security:基于MySQL数据库的身份认证和角色授权

220.Spring Boot+Spring Security:自定义登录页面和构建主页

221.Spring Boot+Spring Security:登出和403处理