update admin

This commit is contained in:
2026-05-06 19:10:27 +08:00
parent e24b41f53c
commit e8f36222e7
25 changed files with 1103 additions and 354 deletions
@@ -1,42 +1,365 @@
package com.yaoyuan.jiscuss.controller;
import com.yaoyuan.jiscuss.entity.Discussion;
import com.yaoyuan.jiscuss.entity.Post;
import com.yaoyuan.jiscuss.entity.Role;
import com.yaoyuan.jiscuss.entity.UpgradeLog;
import com.yaoyuan.jiscuss.entity.User;
import com.yaoyuan.jiscuss.entity.UserInfo;
import com.yaoyuan.jiscuss.entity.UserRole;
import com.yaoyuan.jiscuss.entity.AuditLog;
import com.yaoyuan.jiscuss.repository.DiscussionsRepository;
import com.yaoyuan.jiscuss.repository.DiscussionsTagsRepository;
import com.yaoyuan.jiscuss.repository.PostsRepository;
import com.yaoyuan.jiscuss.repository.RoleRepository;
import com.yaoyuan.jiscuss.repository.UpgradeLogRepository;
import com.yaoyuan.jiscuss.repository.UserRoleRepository;
import com.yaoyuan.jiscuss.repository.UsersRepository;
import com.yaoyuan.jiscuss.repository.AuditLogRepository;
import com.yaoyuan.jiscuss.service.AuditLogService;
import org.springframework.boot.SpringBootVersion;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author yaoyuan2.chu
* 后台系统控制器
*/
@Controller
public class AdminSystemController {
public class AdminSystemController extends BaseController {
/**
* 后台登录
*/
private final UsersRepository usersRepository;
private final DiscussionsRepository discussionsRepository;
private final PostsRepository postsRepository;
private final DiscussionsTagsRepository discussionsTagsRepository;
private final RoleRepository roleRepository;
private final UserRoleRepository userRoleRepository;
private final UpgradeLogRepository upgradeLogRepository;
private final AuditLogRepository auditLogRepository;
private final AuditLogService auditLogService;
/**
* 后台退出
*/
@RequestMapping("/admin/logout")
public String logout(@RequestParam(defaultValue = "discussion") String type, HttpServletRequest request, ModelMap map) {
return "admin/logout";
public AdminSystemController(
UsersRepository usersRepository,
DiscussionsRepository discussionsRepository,
PostsRepository postsRepository,
DiscussionsTagsRepository discussionsTagsRepository,
RoleRepository roleRepository,
UserRoleRepository userRoleRepository,
UpgradeLogRepository upgradeLogRepository,
AuditLogRepository auditLogRepository,
AuditLogService auditLogService) {
this.usersRepository = usersRepository;
this.discussionsRepository = discussionsRepository;
this.postsRepository = postsRepository;
this.discussionsTagsRepository = discussionsTagsRepository;
this.roleRepository = roleRepository;
this.userRoleRepository = userRoleRepository;
this.upgradeLogRepository = upgradeLogRepository;
this.auditLogRepository = auditLogRepository;
this.auditLogService = auditLogService;
}
/**
* 后台设置管理
*/
@GetMapping("/admin/home")
public String home(HttpServletRequest request, ModelMap map) {
fillCommon(request, map, "home");
map.put("userCount", usersRepository.count());
map.put("discussionCount", discussionsRepository.count());
map.put("postCount", postsRepository.count());
map.put("roleCount", roleRepository.count());
map.put("sys", buildSystemMetrics());
map.put("deps", buildDependencyVersions());
/**
* 后台页面
* @return
*/
@RequestMapping("/admin/home")
public String home(@RequestParam(defaultValue = "discussion") String type, HttpServletRequest request, ModelMap map) {
return "admin/home";
}
@GetMapping("/admin/users")
public String users(HttpServletRequest request, ModelMap map) {
fillCommon(request, map, "users");
List<User> users = usersRepository.findAll(Sort.by(Sort.Direction.ASC, "id"));
List<Role> roles = roleRepository.findAllByOrderByIdAsc();
Map<Integer, Set<Integer>> userRoleIds = new HashMap<>();
for (UserRole ur : userRoleRepository.findAll()) {
userRoleIds.computeIfAbsent(ur.getUserId(), key -> new HashSet<>()).add(ur.getRoleId());
}
map.put("users", users);
map.put("roles", roles);
map.put("userRoleIds", userRoleIds);
return "admin/users";
}
@PostMapping("/admin/users/{id}/roles")
@Transactional
public String updateUserRoles(HttpServletRequest request,
@PathVariable("id") Integer id,
@RequestParam(value = "roleIds", required = false) List<Integer> roleIds) {
UserInfo currentAdmin = getUserInfo(request);
userRoleRepository.deleteByUserId(id);
if (roleIds != null) {
Date now = new Date();
Set<Integer> uniqueRoleIds = new HashSet<>(roleIds);
Set<Integer> validEnabledRoleIds = roleRepository.findAllById(uniqueRoleIds).stream()
.filter(role -> role.getEnabled() != null && role.getEnabled() == 1)
.map(Role::getId)
.collect(Collectors.toSet());
for (Integer roleId : validEnabledRoleIds) {
UserRole ur = new UserRole();
ur.setUserId(id);
ur.setRoleId(roleId);
ur.setCreateTime(now);
userRoleRepository.save(ur);
}
}
auditLogService.log(currentAdmin, "update_user_roles", "user", id,
"Updated user role assignments. Role count: " + (roleIds == null ? 0 : roleIds.size()));
return "redirect:/admin/users";
}
@PostMapping("/admin/roles")
public String createRole(HttpServletRequest request,
@RequestParam("code") String code,
@RequestParam("name") String name,
@RequestParam(value = "description", required = false) String description) {
UserInfo currentAdmin = getUserInfo(request);
String normalizedCode = code == null ? "" : code.trim().toUpperCase();
if (normalizedCode.isEmpty()) {
return "redirect:/admin/users";
}
Role exists = roleRepository.findByCodeIgnoreCase(normalizedCode);
if (exists == null) {
Date now = new Date();
Role role = new Role();
role.setCode(normalizedCode);
role.setName(name == null ? "" : name.trim());
role.setDescription(description);
role.setEnabled(1);
role.setCreateTime(now);
role.setUpdateTime(now);
roleRepository.save(role);
auditLogService.log(currentAdmin, "create_role", "role", role.getId(),
"Created role: " + normalizedCode);
} else {
auditLogService.log(currentAdmin, "create_role_duplicate", "role", exists.getId(),
"Attempted to create duplicate role: " + normalizedCode, "ignored");
}
return "redirect:/admin/users";
}
@PostMapping("/admin/roles/{id}/toggle")
public String toggleRole(HttpServletRequest request,
@PathVariable("id") Integer id) {
UserInfo currentAdmin = getUserInfo(request);
Role role = roleRepository.findById(id).orElse(null);
if (role != null) {
int nextStatus = role.getEnabled() != null && role.getEnabled() == 1 ? 0 : 1;
// Keep built-in ADMIN role enabled to avoid locking out management access.
if ("ADMIN".equalsIgnoreCase(role.getCode()) && nextStatus == 0) {
auditLogService.log(currentAdmin, "toggle_role_blocked", "role", id,
"Attempted to disable built-in ADMIN role", "blocked");
return "redirect:/admin/users";
}
role.setEnabled(nextStatus);
role.setUpdateTime(new Date());
roleRepository.save(role);
auditLogService.log(currentAdmin, "toggle_role", "role", id,
"Toggled role status to " + (nextStatus == 1 ? "enabled" : "disabled"));
}
return "redirect:/admin/users";
}
@GetMapping("/admin/discussions")
public String discussions(HttpServletRequest request, ModelMap map) {
fillCommon(request, map, "discussions");
List<Discussion> discussions = discussionsRepository.findAll(Sort.by(Sort.Direction.DESC, "createTime"));
map.put("discussions", discussions);
return "admin/discussions";
}
@PostMapping("/admin/discussions/{id}/delete")
@Transactional
public String deleteDiscussion(HttpServletRequest request,
@PathVariable("id") Integer id) {
UserInfo currentAdmin = getUserInfo(request);
Discussion discussion = discussionsRepository.findById(id).orElse(null);
String title = discussion == null ? "unknown" : discussion.getTitle();
discussionsTagsRepository.deleteByDiscussionId(id);
postsRepository.deleteByDiscussionId(id);
discussionsRepository.deleteById(id);
auditLogService.log(currentAdmin, "delete_discussion", "discussion", id,
"Deleted discussion: " + title);
return "redirect:/admin/discussions";
}
@GetMapping("/admin/posts")
public String posts(HttpServletRequest request, ModelMap map) {
fillCommon(request, map, "posts");
List<Post> posts = postsRepository.findAll(Sort.by(Sort.Direction.DESC, "createTime"));
map.put("posts", posts);
Set<Integer> userIds = posts.stream().map(Post::getCreateId).filter(v -> v != null).collect(Collectors.toSet());
Set<Integer> discussionIds = posts.stream().map(Post::getDiscussionId).filter(v -> v != null).collect(Collectors.toSet());
Map<Integer, String> userNames = usersRepository.findAllById(userIds).stream()
.collect(Collectors.toMap(User::getId, User::getUsername));
Map<Integer, String> discussionNames = discussionsRepository.findAllById(discussionIds).stream()
.collect(Collectors.toMap(Discussion::getId, Discussion::getTitle));
map.put("userNames", userNames);
map.put("discussionNames", discussionNames);
return "admin/posts";
}
@PostMapping("/admin/posts/{id}/delete")
public String deletePost(HttpServletRequest request,
@PathVariable("id") Integer id) {
UserInfo currentAdmin = getUserInfo(request);
Post post = postsRepository.findById(id).orElse(null);
String content = post == null ? "unknown" : (post.getContent() == null ? "" : post.getContent());
if (content.length() > 50) {
content = content.substring(0, 50) + "...";
}
postsRepository.deleteById(id);
auditLogService.log(currentAdmin, "delete_post", "post", id,
"Deleted post: " + content);
return "redirect:/admin/posts";
}
@GetMapping("/admin/upgrade-logs")
public String upgradeLogs(HttpServletRequest request, ModelMap map) {
fillCommon(request, map, "upgradeLogs");
map.put("logs", upgradeLogRepository.findAllByOrderByCreateTimeDesc());
return "admin/upgrade-logs";
}
@PostMapping("/admin/upgrade-logs")
public String createUpgradeLog(HttpServletRequest request,
@RequestParam("version") String version,
@RequestParam("title") String title,
@RequestParam(value = "type", defaultValue = "feature") String type,
@RequestParam("content") String content) {
UserInfo user = getUserInfo(request);
UpgradeLog log = new UpgradeLog();
log.setVersion(version);
log.setTitle(title);
log.setType(type);
log.setContent(content);
log.setCreatedBy(user == null ? null : user.getId());
log.setCreateTime(new Date());
upgradeLogRepository.save(log);
auditLogService.log(user, "create_upgrade_log", "upgrade_log", log.getId(),
"Created upgrade log: " + version + " - " + title);
return "redirect:/admin/upgrade-logs";
}
@GetMapping("/admin/plugins")
public String plugins(HttpServletRequest request, ModelMap map) {
fillCommon(request, map, "plugins");
return "admin/plugins";
}
@GetMapping("/admin/audit-logs")
public String auditLogs(HttpServletRequest request, ModelMap map) {
fillCommon(request, map, "auditLogs");
List<AuditLog> logs = auditLogRepository.findAllByOrderByCreateTimeDesc();
map.put("logs", logs);
return "admin/audit-logs";
}
@GetMapping("/admin/themes")
public String themes(HttpServletRequest request, ModelMap map) {
fillCommon(request, map, "themes");
return "admin/themes";
}
private void fillCommon(HttpServletRequest request, ModelMap map, String active) {
UserInfo user = getUserInfo(request);
map.put("adminName", user == null ? "admin" : user.getUsername());
map.put("active", active);
}
private Map<String, Object> buildSystemMetrics() {
Map<String, Object> result = new HashMap<>();
Runtime rt = Runtime.getRuntime();
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
long totalMb = bytesToMb(rt.totalMemory());
long freeMb = bytesToMb(rt.freeMemory());
long usedMb = totalMb - freeMb;
long maxMb = bytesToMb(rt.maxMemory());
long heapUsedMb = bytesToMb(memoryMXBean.getHeapMemoryUsage().getUsed());
result.put("totalMb", totalMb);
result.put("freeMb", freeMb);
result.put("usedMb", usedMb);
result.put("maxMb", maxMb);
result.put("heapUsedMb", heapUsedMb);
result.put("uptimeMs", ManagementFactory.getRuntimeMXBean().getUptime());
result.put("cpuLoad", readCpuLoadPercent());
return result;
}
private Map<String, String> buildDependencyVersions() {
Map<String, String> result = new HashMap<>();
result.put("springBoot", SpringBootVersion.getVersion());
result.put("java", System.getProperty("java.version"));
result.put("spring", implVersion("org.springframework.core.SpringVersion"));
result.put("hibernate", implVersion("org.hibernate.Version"));
result.put("flyway", implVersion("org.flywaydb.core.Flyway"));
result.put("druid", implVersion("com.alibaba.druid.pool.DruidDataSource"));
result.put("ehcache", implVersion("org.ehcache.CacheManager"));
result.put("springdoc", implVersion("org.springdoc.core.configuration.SpringDocConfiguration"));
return result;
}
private String implVersion(String className) {
try {
Class<?> clazz = Class.forName(className);
Package pkg = clazz.getPackage();
String version = pkg == null ? null : pkg.getImplementationVersion();
return version == null ? "unknown" : version;
} catch (ClassNotFoundException e) {
return "unknown";
}
}
private String readCpuLoadPercent() {
try {
java.lang.management.OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
if (osBean instanceof com.sun.management.OperatingSystemMXBean sunOsBean) {
double value = sunOsBean.getCpuLoad();
if (value >= 0) {
return String.format("%.2f%%", value * 100);
}
}
} catch (Exception ignored) {
}
return "N/A";
}
private long bytesToMb(long bytes) {
return bytes / 1024 / 1024;
}
}
@@ -0,0 +1,47 @@
package com.yaoyuan.jiscuss.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@Entity
@Table(name = "audit_log")
public class AuditLog implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "admin_id")
private Integer adminId;
@Column(name = "admin_name")
private String adminName;
@Column(name = "action_type")
private String actionType;
@Column(name = "target_type")
private String targetType;
@Column(name = "target_id")
private Integer targetId;
@Column(name = "description")
private String description;
@Column(name = "status")
private String status;
@Column(name = "create_time")
private Date createTime;
}
@@ -0,0 +1,41 @@
package com.yaoyuan.jiscuss.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@Entity
@Table(name = "rbac_role")
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "code")
private String code;
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;
@Column(name = "enabled")
private Integer enabled;
@Column(name = "create_time")
private Date createTime;
@Column(name = "update_time")
private Date updateTime;
}
@@ -0,0 +1,41 @@
package com.yaoyuan.jiscuss.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@Entity
@Table(name = "upgrade_log")
public class UpgradeLog implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "version")
private String version;
@Column(name = "title")
private String title;
@Column(name = "content")
private String content;
@Column(name = "type")
private String type;
@Column(name = "created_by")
private Integer createdBy;
@Column(name = "create_time")
private Date createTime;
}
@@ -0,0 +1,32 @@
package com.yaoyuan.jiscuss.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@Entity
@Table(name = "rbac_user_role")
public class UserRole implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "user_id")
private Integer userId;
@Column(name = "role_id")
private Integer roleId;
@Column(name = "create_time")
private Date createTime;
}
@@ -0,0 +1,20 @@
package com.yaoyuan.jiscuss.repository;
import com.yaoyuan.jiscuss.entity.AuditLog;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface AuditLogRepository extends JpaRepository<AuditLog, Integer> {
List<AuditLog> findAllByOrderByCreateTimeDesc();
Page<AuditLog> findAllByOrderByCreateTimeDesc(Pageable pageable);
List<AuditLog> findByTargetTypeAndTargetIdOrderByCreateTimeDesc(String targetType, Integer targetId);
List<AuditLog> findByAdminIdOrderByCreateTimeDesc(Integer adminId);
}
@@ -7,4 +7,5 @@ import org.springframework.stereotype.Repository;
@Repository
public interface DiscussionsTagsRepository extends JpaRepository<DiscussionTag, Integer> {
void deleteByDiscussionId(Integer discussionId);
}
@@ -12,6 +12,8 @@ import java.util.Map;
@Repository
public interface PostsRepository extends JpaRepository<Post, Integer> {
void deleteByDiscussionId(Integer discussionId);
/**
* @param dId
* @return
@@ -0,0 +1,16 @@
package com.yaoyuan.jiscuss.repository;
import com.yaoyuan.jiscuss.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface RoleRepository extends JpaRepository<Role, Integer> {
Role findByCode(String code);
Role findByCodeIgnoreCase(String code);
List<Role> findAllByOrderByIdAsc();
}
@@ -0,0 +1,12 @@
package com.yaoyuan.jiscuss.repository;
import com.yaoyuan.jiscuss.entity.UpgradeLog;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UpgradeLogRepository extends JpaRepository<UpgradeLog, Integer> {
List<UpgradeLog> findAllByOrderByCreateTimeDesc();
}
@@ -0,0 +1,20 @@
package com.yaoyuan.jiscuss.repository;
import com.yaoyuan.jiscuss.entity.UserRole;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRoleRepository extends JpaRepository<UserRole, Integer> {
List<UserRole> findByUserId(Integer userId);
void deleteByUserId(Integer userId);
@Query(value = "select r.code from rbac_user_role ur join rbac_role r on ur.role_id = r.id where ur.user_id = :userId and r.enabled = 1",
nativeQuery = true)
List<String> findRoleCodesByUserId(@Param("userId") Integer userId);
}
@@ -0,0 +1,59 @@
package com.yaoyuan.jiscuss.service;
import com.yaoyuan.jiscuss.entity.AuditLog;
import com.yaoyuan.jiscuss.entity.UserInfo;
import com.yaoyuan.jiscuss.repository.AuditLogRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
/**
* Service for recording admin operations in audit log.
*/
@Service
public class AuditLogService {
private final AuditLogRepository auditLogRepository;
public AuditLogService(AuditLogRepository auditLogRepository) {
this.auditLogRepository = auditLogRepository;
}
@Transactional
public void log(Integer adminId, String adminName, String actionType, String targetType,
Integer targetId, String description, String status) {
AuditLog log = new AuditLog();
log.setAdminId(adminId);
log.setAdminName(adminName);
log.setActionType(actionType);
log.setTargetType(targetType);
log.setTargetId(targetId);
log.setDescription(description);
log.setStatus(status == null ? "success" : status);
log.setCreateTime(new Date());
auditLogRepository.save(log);
}
@Transactional
public void log(Integer adminId, String adminName, String actionType, String targetType,
Integer targetId, String description) {
log(adminId, adminName, actionType, targetType, targetId, description, "success");
}
@Transactional
public void log(UserInfo user, String actionType, String targetType,
Integer targetId, String description) {
Integer userId = user == null ? null : user.getId();
String userName = user == null ? "unknown" : user.getUsername();
log(userId, userName, actionType, targetType, targetId, description, "success");
}
@Transactional
public void log(UserInfo user, String actionType, String targetType,
Integer targetId, String description, String status) {
Integer userId = user == null ? null : user.getId();
String userName = user == null ? "unknown" : user.getUsername();
log(userId, userName, actionType, targetType, targetId, description, status);
}
}
@@ -2,6 +2,7 @@ package com.yaoyuan.jiscuss.service.impl;
import com.yaoyuan.jiscuss.entity.User;
import com.yaoyuan.jiscuss.entity.UserInfo;
import com.yaoyuan.jiscuss.repository.UserRoleRepository;
import com.yaoyuan.jiscuss.service.IUsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
@@ -29,6 +30,9 @@ public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
private IUsersService userInfoService;
@Autowired
private UserRoleRepository userRoleRepository;
@Override
public UserInfo loadUserByUsername(String username) throws UsernameNotFoundException {
User userInfo = userInfoService.getByUsername(username);
@@ -36,11 +40,16 @@ public class UserDetailServiceImpl implements UserDetailsService {
throw new UsernameNotFoundException("用户不存在: " + username);
}
// Assign role based on user level: level >= 1 → ADMIN, else → USER
String role = (userInfo.getLevel() != null && userInfo.getLevel() >= 1) ? "ADMIN" : "USER";
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
List<String> roleCodes = userRoleRepository.findRoleCodesByUserId(userInfo.getId());
if (roleCodes == null || roleCodes.isEmpty()) {
// Compatibility fallback for legacy data before RBAC migration.
String role = (userInfo.getLevel() != null && userInfo.getLevel() >= 1) ? "ADMIN" : "USER";
roleCodes = List.of(role);
}
for (String roleCode : roleCodes) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + roleCode));
}
return new UserInfo(
authorities,