diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..1b1d696 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + mysql.8 + true + com.mysql.cj.jdbc.Driver + jdbc:mysql://localhost:3306 + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 01a1b47..b1b5074 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -5,6 +5,7 @@ + diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000..487f336 --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/common/common-util/pom.xml b/common/common-util/pom.xml index 361414b..290ecfe 100644 --- a/common/common-util/pom.xml +++ b/common/common-util/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-web - provided + io.jsonwebtoken @@ -27,5 +27,11 @@ com.alibaba fastjson + + + io.jsonwebtoken + jjwt + + diff --git a/common/common-util/src/main/java/com/atguigu/common/jwt/JwtHelper.java b/common/common-util/src/main/java/com/atguigu/common/jwt/JwtHelper.java new file mode 100644 index 0000000..4d01496 --- /dev/null +++ b/common/common-util/src/main/java/com/atguigu/common/jwt/JwtHelper.java @@ -0,0 +1,102 @@ +package com.atguigu.common.jwt; + +import io.jsonwebtoken.*; +import org.springframework.util.StringUtils; + +import java.util.Date; + +/** + * ClassName: JitHelper + * Package: com.atguigu.common.jwt + * JWT工具类 + * + * @author yovinchen + * @Create 2023/6/10 16:12 + */ +public class JwtHelper { + + private static final long tokenExpiration = 365L * 24 * 60 * 60 * 1000; + private static final String tokenSignKey = "123456"; + + /** + * 根据用户 id 和用户名称, 生成token的字符串 + * + * @param userId + * @param username + * @return + */ + public static String createToken(Long userId, String username) { + String token = Jwts.builder() + //分类 + .setSubject("AUTH-USER") + + //设置Token有效时长 + .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)) + + //设置主体部分 + .claim("userId", userId) + .claim("username", username) + + //签名部分 + .signWith(SignatureAlgorithm.HS512, tokenSignKey) + .compressWith(CompressionCodecs.GZIP) + .compact(); + return token; + } + + /** + * 从生成的Token中获取id + * + * @param token + * @return + */ + public static Long getUserId(String token) { + try { + if (StringUtils.isEmpty(token)) return null; + + Jws claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); + Claims claims = claimsJws.getBody(); + Integer userId = (Integer) claims.get("userId"); + return userId.longValue(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 从Token中获取用户名称 + * + * @param token + * @return + */ + public static String getUsername(String token) { + try { + if (StringUtils.isEmpty(token)) return ""; + + Jws claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); + Claims claims = claimsJws.getBody(); + return (String) claims.get("username"); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 测试 + * + * @param args + */ + public static void main(String[] args) { + String token = JwtHelper.createToken(1L, "admin"); + System.out.println(token); + String username = JwtHelper.getUsername(token); + Long userId = JwtHelper.getUserId(token); + + System.out.println("username = " + username); + System.out.println("userId = " + userId); + } + +} + diff --git a/common/common-util/src/main/java/com/atguigu/common/result/ResultCodeEnum.java b/common/common-util/src/main/java/com/atguigu/common/result/ResultCodeEnum.java index 2eb7673..679f061 100644 --- a/common/common-util/src/main/java/com/atguigu/common/result/ResultCodeEnum.java +++ b/common/common-util/src/main/java/com/atguigu/common/result/ResultCodeEnum.java @@ -18,7 +18,7 @@ public enum ResultCodeEnum { FAIL(201, "失败"), SERVICE_ERROR(2012, "服务异常"), DATA_ERROR(204, "数据异常"), - + LOGIN_ERROR(205, "认证失败"), LOGIN_AUTH(208, "未登陆"), PERMISSION(209, "没有权限"); diff --git a/common/common-util/src/main/java/com/atguigu/common/utils/MD5.java b/common/common-util/src/main/java/com/atguigu/common/utils/MD5.java new file mode 100644 index 0000000..c9f9b30 --- /dev/null +++ b/common/common-util/src/main/java/com/atguigu/common/utils/MD5.java @@ -0,0 +1,33 @@ +package com.atguigu.common.utils; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public final class MD5 { + + public static String encrypt(String strSrc) { + try { + char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + byte[] bytes = strSrc.getBytes(); + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(bytes); + bytes = md.digest(); + int j = bytes.length; + char[] chars = new char[j * 2]; + int k = 0; + for (byte b : bytes) { + chars[k++] = hexChars[b >>> 4 & 0xf]; + chars[k++] = hexChars[b & 0xf]; + } + return new String(chars); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + throw new RuntimeException("MD5加密出错!!+" + e); + } + } + + public static void main(String[] args) { + System.out.println(MD5.encrypt("111111")); + } +} diff --git a/common/common-util/src/main/java/com/atguigu/common/utils/ResponseUtil.java b/common/common-util/src/main/java/com/atguigu/common/utils/ResponseUtil.java new file mode 100644 index 0000000..ff0cb93 --- /dev/null +++ b/common/common-util/src/main/java/com/atguigu/common/utils/ResponseUtil.java @@ -0,0 +1,30 @@ +package com.atguigu.common.utils; + +import com.atguigu.common.result.Result; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * ClassName: ResponseUtil + * Package: com.atguigu.common.utils + * + * @author yovinchen + * @Create 2023/6/10 23:42 + */ +public class ResponseUtil { + + public static void out(HttpServletResponse response, Result r) { + ObjectMapper mapper = new ObjectMapper(); + response.setStatus(HttpStatus.OK.value()); + response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + try { + mapper.writeValue(response.getWriter(), r); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/common/spring-security/.gitignore b/common/spring-security/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/common/spring-security/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/common/spring-security/pom.xml b/common/spring-security/pom.xml new file mode 100644 index 0000000..7bf3fee --- /dev/null +++ b/common/spring-security/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + com.atguigu + guigu-oa-parent + 1.0-SNAPSHOT + ../../pom.xml + + + spring-security + + + 8 + 8 + UTF-8 + + + + com.atguigu + common-util + 1.0-SNAPSHOT + + + com.atguigu + model + 1.0-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + provided + + + diff --git a/common/spring-security/src/main/java/com/atguigu/security/config/WebSecurityConfig.java b/common/spring-security/src/main/java/com/atguigu/security/config/WebSecurityConfig.java new file mode 100644 index 0000000..7c3edc7 --- /dev/null +++ b/common/spring-security/src/main/java/com/atguigu/security/config/WebSecurityConfig.java @@ -0,0 +1,19 @@ +package com.atguigu.security.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +/** + * ClassName: WebSecurityConfig + * Package: com.atguigu.security.config + * + * @author yovinchen + * @Create 2023/6/10 22:47 + */ +@Configuration +//@EnableWebSecurity是开启SpringSecurity的默认行为 +@EnableWebSecurity +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + +} diff --git a/common/spring-security/src/main/java/com/atguigu/security/custom/CustomMd5PasswordEncoder.java b/common/spring-security/src/main/java/com/atguigu/security/custom/CustomMd5PasswordEncoder.java new file mode 100644 index 0000000..a08b82a --- /dev/null +++ b/common/spring-security/src/main/java/com/atguigu/security/custom/CustomMd5PasswordEncoder.java @@ -0,0 +1,25 @@ +package com.atguigu.security.custom; + +import com.atguigu.common.utils.MD5; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +/** + * ClassName: CustomMd5PasswordEncoder + * Package: com.atguigu.security.custom + * 密码处理 + * + * @author yovinchen + * @Create 2023/6/10 23:23 + */ +@Component +public class CustomMd5PasswordEncoder implements PasswordEncoder { + + public String encode(CharSequence rawPassword) { + return MD5.encrypt(rawPassword.toString()); + } + + public boolean matches(CharSequence rawPassword, String encodedPassword) { + return encodedPassword.equals(MD5.encrypt(rawPassword.toString())); + } +} diff --git a/common/spring-security/src/main/java/com/atguigu/security/custom/CustomUser.java b/common/spring-security/src/main/java/com/atguigu/security/custom/CustomUser.java new file mode 100644 index 0000000..8eedbe2 --- /dev/null +++ b/common/spring-security/src/main/java/com/atguigu/security/custom/CustomUser.java @@ -0,0 +1,36 @@ +package com.atguigu.security.custom; + +import com.atguigu.model.system.SysUser; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.User; + +import java.util.Collection; + +/** + * ClassName: CustomUser + * Package: com.atguigu.security.custom + * + * @author yovinchen + * @Create 2023/6/10 23:24 + */ +public class CustomUser extends User { + + /** + * 我们自己的用户实体对象,要调取用户信息时直接获取这个实体对象。(这里我就不写get/set方法了) + */ + private SysUser sysUser; + + public CustomUser(SysUser sysUser, Collection authorities) { + super(sysUser.getUsername(), sysUser.getPassword(), authorities); + this.sysUser = sysUser; + } + + public SysUser getSysUser() { + return sysUser; + } + + public void setSysUser(SysUser sysUser) { + this.sysUser = sysUser; + } + +} diff --git a/common/spring-security/src/main/java/com/atguigu/security/custom/UserDetailsService.java b/common/spring-security/src/main/java/com/atguigu/security/custom/UserDetailsService.java new file mode 100644 index 0000000..2463548 --- /dev/null +++ b/common/spring-security/src/main/java/com/atguigu/security/custom/UserDetailsService.java @@ -0,0 +1,23 @@ +package com.atguigu.security.custom; + +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +/** + * ClassName: UserDetailsService + * Package: com.atguigu.security.custom + * + * @author yovinchen + * @Create 2023/6/10 23:28 + */ +public interface UserDetailsService { + + /** + * 根据用户名获取用户对象(获取不到直接抛异常) + * + * @param username + * @return + * @throws UsernameNotFoundException + */ + UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; +} diff --git a/common/spring-security/src/main/java/com/atguigu/security/filter/TokenAuthenticationFilter.java b/common/spring-security/src/main/java/com/atguigu/security/filter/TokenAuthenticationFilter.java new file mode 100644 index 0000000..a215cc2 --- /dev/null +++ b/common/spring-security/src/main/java/com/atguigu/security/filter/TokenAuthenticationFilter.java @@ -0,0 +1,64 @@ +package com.atguigu.security.filter; + +import com.atguigu.common.jwt.JwtHelper; +import com.atguigu.common.result.Result; +import com.atguigu.common.result.ResultCodeEnum; +import com.atguigu.common.utils.ResponseUtil; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Collections; + +/** + * ClassName: TokenAuthenticationFilter + * Package: com.atguigu.security.custom.filter + * 认证解析token过滤器 + * + * @author yovinchen + * @Create 2023/6/10 23:45 + */ +public class TokenAuthenticationFilter extends OncePerRequestFilter { + + public TokenAuthenticationFilter() { + + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { + logger.info("uri:" + request.getRequestURI()); + //如果是登录接口,直接放行 + if ("/admin/system/index/login".equals(request.getRequestURI())) { + chain.doFilter(request, response); + return; + } + + UsernamePasswordAuthenticationToken authentication = getAuthentication(request); + if (null != authentication) { + SecurityContextHolder.getContext().setAuthentication(authentication); + chain.doFilter(request, response); + } else { + ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_ERROR)); + } + } + + private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) { + // token置于header里 + String token = request.getHeader("token"); + logger.info("token:" + token); + if (!StringUtils.isEmpty(token)) { + String useruame = JwtHelper.getUsername(token); + logger.info("useruame:" + useruame); + if (!StringUtils.isEmpty(useruame)) { + return new UsernamePasswordAuthenticationToken(useruame, null, Collections.emptyList()); + } + } + return null; + } +} diff --git a/common/spring-security/src/main/java/com/atguigu/security/filter/TokenLoginFilter.java b/common/spring-security/src/main/java/com/atguigu/security/filter/TokenLoginFilter.java new file mode 100644 index 0000000..631e0a7 --- /dev/null +++ b/common/spring-security/src/main/java/com/atguigu/security/filter/TokenLoginFilter.java @@ -0,0 +1,90 @@ +package com.atguigu.security.filter; + +import com.atguigu.common.jwt.JwtHelper; +import com.atguigu.common.result.Result; +import com.atguigu.common.result.ResultCodeEnum; +import com.atguigu.common.utils.ResponseUtil; +import com.atguigu.security.custom.CustomUser; +import com.atguigu.vo.system.LoginVo; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * ClassName: TokenLoginFilter + * Package: com.atguigu.security.custom.filter + * 登录过滤器,继承UsernamePasswordAuthenticationFilter,对用户名密码进行登录校验 + * + * @author yovinchen + * @Create 2023/6/10 23:37 + */ +public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter { + + // 构造方法 + public TokenLoginFilter(AuthenticationManager authenticationManager) { + this.setAuthenticationManager(authenticationManager); + this.setPostOnly(false); + //指定登录接口及提交方式,可以指定任意路径 + this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login", "POST")); + } + + // 登录认证过程 + // 获取输入的用户名和密码,调用方法认证 + @Override + public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) + throws AuthenticationException { + try { + // 获取用户信息 + LoginVo loginVo = new ObjectMapper().readValue(req.getInputStream(), LoginVo.class); + + //封装对象 + Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword()); + + //调用方法 + return this.getAuthenticationManager().authenticate(authenticationToken); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + // 认证成功调用的方法 + @Override + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, + Authentication auth) throws IOException, ServletException { + // 获取当前用户 + CustomUser customUser = (CustomUser) auth.getPrincipal(); + + // 生成token + String token = JwtHelper.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername()); + + // 返回 + Map map = new HashMap<>(); + map.put("token", token); + ResponseUtil.out(response, Result.ok(map)); + } + + // 认证失败调用的方法 + @Override + protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, + AuthenticationException e) throws IOException, ServletException { + + if (e.getCause() instanceof RuntimeException) { + ResponseUtil.out(response, Result.build(null, ResultCodeEnum.DATA_ERROR)); + } else { + ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_AUTH)); + } + } + +} diff --git a/model/src/main/java/com/atguigu/model/system/SysRoleMenu.java b/model/src/main/java/com/atguigu/model/system/SysRoleMenu.java index 7fb8a39..0df4a64 100644 --- a/model/src/main/java/com/atguigu/model/system/SysRoleMenu.java +++ b/model/src/main/java/com/atguigu/model/system/SysRoleMenu.java @@ -2,6 +2,7 @@ package com.atguigu.model.system; import com.atguigu.model.base.BaseEntity; import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -11,7 +12,7 @@ import lombok.Data; @ApiModel(description = "角色菜单") @TableName("sys_role_menu") public class SysRoleMenu extends BaseEntity { - + private static final long serialVersionUID = 1L; @ApiModelProperty(value = "角色id") diff --git a/pom.xml b/pom.xml index 1d0f755..8a51434 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,7 @@ common model service-oa + common/spring-security diff --git a/service-oa/pom.xml b/service-oa/pom.xml index 67f7e6c..9f66b76 100644 --- a/service-oa/pom.xml +++ b/service-oa/pom.xml @@ -20,6 +20,11 @@ service-util 1.0-SNAPSHOT + + com.atguigu + spring-security + 1.0-SNAPSHOT + org.springframework.boot @@ -27,7 +32,7 @@ test - + com.baomidou mybatis-plus-generator @@ -49,5 +54,25 @@ spring-boot-maven-plugin + + + src/main/java + + **/*.yml + **/*.properties + **/*.xml + + false + + + src/main/resources + + **/*.yml + **/*.properties + **/*.xml + + false + + diff --git a/service-oa/src/main/java/com/atguigu/auth/controller/IndexController.java b/service-oa/src/main/java/com/atguigu/auth/controller/IndexController.java index 57e6f5c..ab68c21 100644 --- a/service-oa/src/main/java/com/atguigu/auth/controller/IndexController.java +++ b/service-oa/src/main/java/com/atguigu/auth/controller/IndexController.java @@ -1,23 +1,33 @@ package com.atguigu.auth.controller; +import com.atguigu.auth.service.SysMenuService; +import com.atguigu.auth.service.SysUserService; +import com.atguigu.common.execption.GuiguException; +import com.atguigu.common.jwt.JwtHelper; import com.atguigu.common.result.Result; +import com.atguigu.common.utils.MD5; +import com.atguigu.model.system.SysUser; +import com.atguigu.vo.system.LoginVo; +import com.atguigu.vo.system.RouterVo; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Objects; /** * ClassName: IndexController * Package: com.atguigu.auth.controller + * 后台登录登出 * * @author yovinchen * @Create 2023/6/8 20:32 - * 后台登录登出 */ @Api(tags = "后台登录管理") @RestController @@ -25,6 +35,11 @@ import java.util.Map; public class IndexController { + @Autowired + private SysMenuService sysMenuService; + @Autowired + private SysUserService sysUserService; + /** * 登录 * @@ -32,9 +47,29 @@ public class IndexController { */ @ApiOperation("登陆") @PostMapping("login") - public Result login() { + public Result login(@RequestBody LoginVo loginVo) { +// Map map = new HashMap<>(); +// map.put("token", "admin"); +// return Result.ok(map); + + //获取输入用户名和密码,根据用户名查询数据库 + SysUser sysUser = sysUserService.getOne(new LambdaQueryWrapper().eq(SysUser::getUsername, loginVo.getUsername())); + //用户信息是否存在 + if (sysUser == null) { + throw new GuiguException(201, "用户不存在"); + } + //判断密码 + if (!Objects.equals(sysUser.getPassword(), MD5.encrypt(loginVo.getPassword()))) { + throw new GuiguException(201, "密码错误"); + } + //判断用户是否被禁用 + if (sysUser.getStatus() == 0) { + throw new GuiguException(201, "用户已经被禁用,请联系管理员"); + } + //利用 JWT 根据用户的id和用户名生成Token Map map = new HashMap<>(); - map.put("token", "admin"); + map.put("token", JwtHelper.createToken(sysUser.getId(), sysUser.getUsername())); + //返回 return Result.ok(map); } @@ -45,11 +80,33 @@ public class IndexController { */ @ApiOperation("获取用户信息") @GetMapping("info") - public Result info() { + public Result info(HttpServletRequest request) { + + //获取请求头中Token字符串,解密出用户信息 + String token = request.getHeader("token"); + + //根据用户信息查询数据库,获取用户信息 + Long userId =JwtHelper.getUserId(token); + SysUser sysUser = sysUserService.getById(userId); + + //根据用户id获取用户可以操作菜单列表 + //查询数据库,动态构建路由结构 + List routerList = sysMenuService.findUserMenuListByUserId(userId); + + //根据用户id获取用户可以操作按钮列表 + List permsList = sysMenuService.findUserPermsByUserId(userId); + + //返回相应数据 Map map = new HashMap<>(); map.put("roles", "[admin]"); - map.put("name", "admin"); + map.put("name", sysUser.getName()); map.put("avatar", "https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg"); + + // 返回用户可以操作的菜单 + map.put("routers", routerList); + + // 返回用户可以操作的按钮 + map.put("buttons", permsList); return Result.ok(map); } diff --git a/service-oa/src/main/java/com/atguigu/auth/controller/SysMenuController.java b/service-oa/src/main/java/com/atguigu/auth/controller/SysMenuController.java index 1e89999..53cd03d 100644 --- a/service-oa/src/main/java/com/atguigu/auth/controller/SysMenuController.java +++ b/service-oa/src/main/java/com/atguigu/auth/controller/SysMenuController.java @@ -34,9 +34,9 @@ public class SysMenuController { * @return */ @ApiOperation(value = "根据角色获取菜单") - @GetMapping("toAssign/{roleId}") + @GetMapping("/toAssign/{roleId}") public Result toAssign(@PathVariable Long roleId) { - List list = sysMenuService.findSysMenuByRoleId(roleId); + List list = sysMenuService.findMenuByRoleId(roleId); return Result.ok(list); } diff --git a/service-oa/src/main/java/com/atguigu/auth/controller/SysUserController.java b/service-oa/src/main/java/com/atguigu/auth/controller/SysUserController.java index 95bbede..614829d 100644 --- a/service-oa/src/main/java/com/atguigu/auth/controller/SysUserController.java +++ b/service-oa/src/main/java/com/atguigu/auth/controller/SysUserController.java @@ -3,6 +3,7 @@ package com.atguigu.auth.controller; import com.atguigu.auth.service.SysUserService; import com.atguigu.common.result.Result; +import com.atguigu.common.utils.MD5; import com.atguigu.model.system.SysUser; import com.atguigu.vo.system.SysUserQueryVo; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -107,6 +108,8 @@ public class SysUserController { @ApiOperation(value = "保存用户") @PostMapping("save") public Result save(@RequestBody SysUser user) { + //对密码进行MD5加密,只能加密不能解密 + user.setPassword(MD5.encrypt(user.getPassword())); sysUserService.save(user); return Result.ok(); } diff --git a/service-oa/src/main/java/com/atguigu/auth/mapper/SysMenuMapper.java b/service-oa/src/main/java/com/atguigu/auth/mapper/SysMenuMapper.java index be7eb56..918a7b9 100644 --- a/service-oa/src/main/java/com/atguigu/auth/mapper/SysMenuMapper.java +++ b/service-oa/src/main/java/com/atguigu/auth/mapper/SysMenuMapper.java @@ -2,6 +2,9 @@ package com.atguigu.auth.mapper; import com.atguigu.model.system.SysMenu; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; /** *

@@ -13,4 +16,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; */ public interface SysMenuMapper extends BaseMapper { + /** + * 多表关联查询:用户角色关系表、角色菜单关系表、菜单表 + * + * @param userId + * @return + */ + List findUserMenuListByUserId(@Param("userId") Long userId); } diff --git a/service-oa/src/main/java/com/atguigu/auth/mapper/xml/SysMenuMapper.xml b/service-oa/src/main/java/com/atguigu/auth/mapper/xml/SysMenuMapper.xml index 31098d7..3930c09 100644 --- a/service-oa/src/main/java/com/atguigu/auth/mapper/xml/SysMenuMapper.xml +++ b/service-oa/src/main/java/com/atguigu/auth/mapper/xml/SysMenuMapper.xml @@ -1,5 +1,31 @@ + + + diff --git a/service-oa/src/main/java/com/atguigu/auth/service/SysMenuService.java b/service-oa/src/main/java/com/atguigu/auth/service/SysMenuService.java index 0f9e87c..67b5279 100644 --- a/service-oa/src/main/java/com/atguigu/auth/service/SysMenuService.java +++ b/service-oa/src/main/java/com/atguigu/auth/service/SysMenuService.java @@ -2,6 +2,7 @@ package com.atguigu.auth.service; import com.atguigu.model.system.SysMenu; import com.atguigu.vo.system.AssginMenuVo; +import com.atguigu.vo.system.RouterVo; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; @@ -36,7 +37,7 @@ public interface SysMenuService extends IService { * @param roleId * @return */ - List findSysMenuByRoleId(Long roleId); + List findMenuByRoleId(Long roleId); /** * 给角色分配权限 @@ -44,4 +45,20 @@ public interface SysMenuService extends IService { * @param assignMenuVo */ void doAssign(AssginMenuVo assignMenuVo); + + /** + * 获取用户操作菜单 + * + * @param userId + * @return + */ + List findUserMenuListByUserId(Long userId); + + /** + * 获取用户操作按钮 + * + * @param userId + * @return + */ + List findUserPermsByUserId(Long userId); } diff --git a/service-oa/src/main/java/com/atguigu/auth/service/SysRoleService.java b/service-oa/src/main/java/com/atguigu/auth/service/SysRoleService.java index e7730c8..3efc4e9 100644 --- a/service-oa/src/main/java/com/atguigu/auth/service/SysRoleService.java +++ b/service-oa/src/main/java/com/atguigu/auth/service/SysRoleService.java @@ -15,10 +15,18 @@ import java.util.Map; */ public interface SysRoleService extends IService { - //查询所有角色和当前用户所属角色 + /** + * 查询所有角色和当前用户所属角色 + * + * @param userId + * @return + */ Map findRoleByUserId(Long userId); - //为用户分配角色 - + /** + * 为用户分配角色 + * + * @param assginRoleVo + */ void doAssign(AssginRoleVo assginRoleVo); } diff --git a/service-oa/src/main/java/com/atguigu/auth/service/SysUserService.java b/service-oa/src/main/java/com/atguigu/auth/service/SysUserService.java index ccec3eb..0a80652 100644 --- a/service-oa/src/main/java/com/atguigu/auth/service/SysUserService.java +++ b/service-oa/src/main/java/com/atguigu/auth/service/SysUserService.java @@ -20,4 +20,12 @@ public interface SysUserService extends IService { * @param status */ void updateStatus(Long id, Integer status); + + /** + * 根据用户名进行查询 + * + * @param username + * @return + */ + SysUser getByUsername(String username); } diff --git a/service-oa/src/main/java/com/atguigu/auth/service/impl/SysMenuServiceImpl.java b/service-oa/src/main/java/com/atguigu/auth/service/impl/SysMenuServiceImpl.java index f7569df..422781b 100644 --- a/service-oa/src/main/java/com/atguigu/auth/service/impl/SysMenuServiceImpl.java +++ b/service-oa/src/main/java/com/atguigu/auth/service/impl/SysMenuServiceImpl.java @@ -1,18 +1,23 @@ package com.atguigu.auth.service.impl; import com.atguigu.auth.mapper.SysMenuMapper; -import com.atguigu.auth.mapper.SysRoleMenuMapper; import com.atguigu.auth.service.SysMenuService; +import com.atguigu.auth.service.SysRoleMenuService; import com.atguigu.auth.utils.MenuHelper; import com.atguigu.common.execption.GuiguException; import com.atguigu.model.system.SysMenu; import com.atguigu.model.system.SysRoleMenu; import com.atguigu.vo.system.AssginMenuVo; +import com.atguigu.vo.system.MetaVo; +import com.atguigu.vo.system.RouterVo; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -27,8 +32,8 @@ import java.util.stream.Collectors; @Service public class SysMenuServiceImpl extends ServiceImpl implements SysMenuService { - - private SysRoleMenuMapper sysRoleMenuMapper; + @Autowired + private SysRoleMenuService sysRoleMenuService; /** * 菜单列表 @@ -71,24 +76,36 @@ public class SysMenuServiceImpl extends ServiceImpl impl * @return */ @Override - public List findSysMenuByRoleId(Long roleId) { - //查询所有菜单 - List allSysMenuList = this.list(new LambdaQueryWrapper().eq(SysMenu::getStatus, 1)); + public List findMenuByRoleId(Long roleId) { + //1 查询所有菜单- 添加条件 status=1 - //在角色菜单关系表中,根据角色id获取角色对应的所有菜单id - List sysRoleMenuList = sysRoleMenuMapper.selectList(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, roleId)); - //根据获取菜单id,获取对应菜单对象 +// LambdaQueryWrapper wrapperSysMenu = new LambdaQueryWrapper<>(); +// wrapperSysMenu.eq(SysMenu::getStatus, 1); +// List allSysMenuList = baseMapper.selectList(wrapperSysMenu); + + List allSysMenuList = baseMapper.selectList(new LambdaQueryWrapper().eq(SysMenu::getStatus, 1)); + + //2 根据角色id roleId查询 角色菜单关系表里面 角色id对应所有的菜单id +// LambdaQueryWrapper wrapperSysRoleMenu = new LambdaQueryWrapper<>(); +// wrapperSysRoleMenu.eq(SysRoleMenu::getRoleId, roleId); +// List sysRoleMenuList = sysRoleMenuService.list(wrapperSysRoleMenu); + + List sysRoleMenuList = sysRoleMenuService.list(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, roleId)); + //3 根据获取菜单id,获取对应菜单对象 List menuIdList = sysRoleMenuList.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList()); - //根据菜单id,和所有菜单集合中id比较,相同则封装 - allSysMenuList.forEach(permission -> { - if (menuIdList.contains(permission.getId())) { - permission.setSelect(true); + + //3.1 拿着菜单id 和所有菜单集合里面id进行比较,如果相同封装 + allSysMenuList.forEach(item -> { + if (menuIdList.contains(item.getId())) { + item.setSelect(true); } else { - permission.setSelect(false); + item.setSelect(false); } }); - //返回规定格式的菜单列表 - return MenuHelper.buildTree(allSysMenuList); + + //4 返回规定树形显示格式菜单列表 + List sysMenuList = MenuHelper.buildTree(allSysMenuList); + return sysMenuList; } /** @@ -99,7 +116,7 @@ public class SysMenuServiceImpl extends ServiceImpl impl @Override public void doAssign(AssginMenuVo assignMenuVo) { //根据角色id 删除菜单角色表 分配数据 - sysRoleMenuMapper.delete(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, assignMenuVo.getRoleId())); + sysRoleMenuService.remove(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, assignMenuVo.getRoleId())); //从参数里面获取角色新分配菜单id列表, //进行遍历,把每个id 数据添加菜单角色表 for (Long menuId : assignMenuVo.getMenuIdList()) { @@ -107,8 +124,132 @@ public class SysMenuServiceImpl extends ServiceImpl impl SysRoleMenu rolePermission = new SysRoleMenu(); rolePermission.setRoleId(assignMenuVo.getRoleId()); rolePermission.setMenuId(menuId); - sysRoleMenuMapper.insert(rolePermission); + sysRoleMenuService.save(rolePermission); } } + /** + * 获取用户操作菜单 + * + * @param userId + * @return + */ + @Override + public List findUserMenuListByUserId(Long userId) { + List sysMenusList = null; + + // 1、判断当前用户是否是管理员 userId=1 是管理员 + // 1.1、 如果是管理员,查询所有菜单列表 + if (userId == 1) { + // 查询所有菜单列表 + sysMenusList = baseMapper.selectList(new LambdaQueryWrapper().eq(SysMenu::getStatus, 1).orderByAsc(SysMenu::getSortValue)); + } else { + + // 1.2、如果不是管理员,根据 userId 查询可以操作菜单列表 + // 多表关联查询:sys_role、sys_role_menu、sys_menu + sysMenusList = baseMapper.findUserMenuListByUserId(userId); + } + // 2、把查询出来的数据列表, 构建成框架要求的路由结构 + // 先构建树形结构 + List sysMenuTreeList = MenuHelper.buildTree(sysMenusList); + // 构建框架要求的路由结构 + return this.buildRouter(sysMenuTreeList); + } + + /** + * 构建框架要求的路由结构 + * + * @param menus + * @return + */ + private List buildRouter(List menus) { + // 创建 list 集合,存值最终数据 + List routers = new ArrayList<>(); + // menus 遍历 + for (SysMenu menu : menus) { + RouterVo router = new RouterVo(); + router.setHidden(false); + router.setAlwaysShow(false); + router.setPath(getRouterPath(menu)); + router.setComponent(menu.getComponent()); + router.setMeta(new MetaVo(menu.getName(), menu.getIcon())); + // 下一层数据 + List children = menu.getChildren(); + if (menu.getType() == 1) { + // 加载隐藏路由 + List hiddenMenuList = children.stream() + .filter(item -> !StringUtils.isEmpty(item.getComponent())) + .collect(Collectors.toList()); + for (SysMenu hiddenMenu : hiddenMenuList) { + RouterVo hiddenRouter = new RouterVo(); + hiddenRouter.setHidden(true); + hiddenRouter.setAlwaysShow(false); + hiddenRouter.setPath(getRouterPath(hiddenMenu)); + hiddenRouter.setComponent(hiddenMenu.getComponent()); + hiddenRouter.setMeta(new MetaVo(hiddenMenu.getName(), hiddenMenu.getIcon())); + routers.add(hiddenRouter); + } + } else { + if (!CollectionUtils.isEmpty(children)) { + if (children.size() > 0) { + router.setAlwaysShow(true); + } + // 递归 + router.setChildren(buildRouter(children)); + } + } + routers.add(router); + } + return routers; + + } + + /** + * 获取路由地址 + * + * @param menu 菜单信息 + * @return 路由地址 + */ + public String getRouterPath(SysMenu menu) { + String routerPath = "/" + menu.getPath(); + if (menu.getParentId().intValue() != 0) { + routerPath = menu.getPath(); + } + return routerPath; + } + + /** + * 获取用户操作按钮 + * + * @param userId + * @return + */ + @Override + public List findUserPermsByUserId(Long userId) { + // 1、判断是否是管理员,如果是管理员,查询所有按钮列表 + List sysMenusList = null; + if (userId == 1) { + // 查询所有菜单列表 + sysMenusList = baseMapper.selectList(new LambdaQueryWrapper().eq(SysMenu::getStatus, 1)); + } else { + // 2、如果不是管理员,根据userId查询可以操作按钮列表 + // 多表关联查询:sys_role、sys_role_menu、sys_menu + sysMenusList = baseMapper.findUserMenuListByUserId(userId); + } + + // 3、从查询出来的数据里面,获取可以操作按钮值的List集合,返回 +// List resultList = new ArrayList<>(); +// for (SysMenu item : sysMenusList) { +// if (item.getType() == 2) { +// resultList.add(item.getPerms()); +// } +// } +// return resultList; + + return sysMenusList.stream() + .filter(item -> item.getType() == 2) + .map(SysMenu::getPerms) + .collect(Collectors.toList()); + } + } diff --git a/service-oa/src/main/java/com/atguigu/auth/service/impl/SysUserServiceImpl.java b/service-oa/src/main/java/com/atguigu/auth/service/impl/SysUserServiceImpl.java index 3b55418..a7f0cf2 100644 --- a/service-oa/src/main/java/com/atguigu/auth/service/impl/SysUserServiceImpl.java +++ b/service-oa/src/main/java/com/atguigu/auth/service/impl/SysUserServiceImpl.java @@ -3,6 +3,7 @@ package com.atguigu.auth.service.impl; import com.atguigu.auth.mapper.SysUserMapper; import com.atguigu.auth.service.SysUserService; import com.atguigu.model.system.SysUser; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -37,4 +38,15 @@ public class SysUserServiceImpl extends ServiceImpl impl } baseMapper.updateById(sysUser); } + + /** + * 根据用户名进行查询 + * + * @param username + * @return + */ + @Override + public SysUser getByUsername(String username) { + return baseMapper.selectOne(new LambdaQueryWrapper().eq(SysUser::getUsername, username)); + } } diff --git a/service-oa/src/main/java/com/atguigu/auth/service/impl/UserDetailsServiceImpl.java b/service-oa/src/main/java/com/atguigu/auth/service/impl/UserDetailsServiceImpl.java new file mode 100644 index 0000000..e173172 --- /dev/null +++ b/service-oa/src/main/java/com/atguigu/auth/service/impl/UserDetailsServiceImpl.java @@ -0,0 +1,39 @@ +package com.atguigu.auth.service.impl; + +import com.atguigu.auth.service.SysUserService; +import com.atguigu.model.system.SysUser; +import com.atguigu.security.custom.CustomUser; +import com.atguigu.security.custom.UserDetailsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; + +import java.util.Collections; + +/** + * ClassName: UserDetailsServiceImpl + * Package: com.atguigu.auth.service.impl + * + * @author yovinchen + * @Create 2023/6/10 23:31 + */ +@Component +public class UserDetailsServiceImpl implements UserDetailsService { + + @Autowired + private SysUserService sysUserService; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + SysUser sysUser = sysUserService.getByUsername(username); + if(null == sysUser) { + throw new UsernameNotFoundException("用户名不存在!"); + } + + if(sysUser.getStatus() == 0) { + throw new RuntimeException("账号已停用"); + } + return new CustomUser(sysUser, Collections.emptyList()); + } +} diff --git a/service-oa/src/main/resources/application-dev.yml b/service-oa/src/main/resources/application-dev.yml index 68ac13b..2fd38d7 100644 --- a/service-oa/src/main/resources/application-dev.yml +++ b/service-oa/src/main/resources/application-dev.yml @@ -4,6 +4,8 @@ mybatis-plus: configuration: # 查看日志 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + mapper-locations: classpath:com/atguigu/auth/mapper/xml/*.xml + spring: datasource: type: com.zaxxer.hikari.HikariDataSource