From 760bb924794f4bb400f67d1c089aee402d06004b Mon Sep 17 00:00:00 2001 From: bunny <1319900154@qq.com> Date: Sat, 27 Apr 2024 00:42:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E4=BF=AE=E6=94=B9):=20:rocket:=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9springSecurity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/misc.xml | 2 +- .../atguigu/common/utlis/BaseContext.java} | 5 ++- .../target/classes/com/atguigu/CodeGet.class | Bin 4085 -> 0 bytes .../atguigu/config/MybatisPlusConfig.class | Bin 1867 -> 0 bytes .../atguigu/constant/MessageConstant.class | Bin 2135 -> 0 bytes .../com/atguigu/context/BaseContext.class | Bin 1484 -> 0 bytes .../security/config/WebSecurityConfig.java | 15 ++++---- .../atguigu/security/custom/CustomUser.java | 2 -- .../filter/TokenAuthenticationFilter.java | 6 ++-- .../UserDetailsService.java | 2 +- .../service/impl/UserDetailsServiceImpl.java | 2 +- service-oa/target/classes/application-dev.yml | 21 ----------- service-oa/target/classes/application.yml | 34 ------------------ service-oa/target/classes/banner.txt | 16 --------- service-oa/target/classes/favicon.ico | Bin 17014 -> 0 bytes 15 files changed, 14 insertions(+), 91 deletions(-) rename common/{spring-security/src/main/java/com/atguigu/security/custom/LoginUserInfoHelper.java => common-util/src/main/java/com/atguigu/common/utlis/BaseContext.java} (89%) delete mode 100644 common/service-util/target/classes/com/atguigu/CodeGet.class delete mode 100644 common/service-util/target/classes/com/atguigu/config/MybatisPlusConfig.class delete mode 100644 common/service-util/target/classes/com/atguigu/constant/MessageConstant.class delete mode 100644 common/service-util/target/classes/com/atguigu/context/BaseContext.class rename common/spring-security/src/main/java/com/atguigu/security/{custom => service}/UserDetailsService.java (93%) delete mode 100644 service-oa/target/classes/application-dev.yml delete mode 100644 service-oa/target/classes/application.yml delete mode 100644 service-oa/target/classes/banner.txt delete mode 100644 service-oa/target/classes/favicon.ico diff --git a/.idea/misc.xml b/.idea/misc.xml index 9134c12..79f13d2 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -9,5 +9,5 @@ - + \ No newline at end of file diff --git a/common/spring-security/src/main/java/com/atguigu/security/custom/LoginUserInfoHelper.java b/common/common-util/src/main/java/com/atguigu/common/utlis/BaseContext.java similarity index 89% rename from common/spring-security/src/main/java/com/atguigu/security/custom/LoginUserInfoHelper.java rename to common/common-util/src/main/java/com/atguigu/common/utlis/BaseContext.java index 039036d..b0dc6d9 100644 --- a/common/spring-security/src/main/java/com/atguigu/security/custom/LoginUserInfoHelper.java +++ b/common/common-util/src/main/java/com/atguigu/common/utlis/BaseContext.java @@ -1,7 +1,6 @@ -package com.atguigu.security.custom; - -public class LoginUserInfoHelper { +package com.atguigu.common.utlis; +public class BaseContext { private static final ThreadLocal userId = new ThreadLocal(); private static final ThreadLocal username = new ThreadLocal(); diff --git a/common/service-util/target/classes/com/atguigu/CodeGet.class b/common/service-util/target/classes/com/atguigu/CodeGet.class deleted file mode 100644 index b9e4bfa2afb39c1234b5938560fd5e198c681722..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4085 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 CMv;2} diff --git a/common/service-util/target/classes/com/atguigu/context/BaseContext.class b/common/service-util/target/classes/com/atguigu/context/BaseContext.class deleted file mode 100644 index be58c65410bf62645a8c8d2ba3b9865028c9f80f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1484 zcmai!YflqF6o%iSmu;5?DilF1mWyaxg?d3mTOmqfLQ*dYSmP(Mw3D)=?IznT`m?+w zkZ5B3?2j_Ov)jv7Ht|Du=FFUP-e=C7>F+<^e*)OVGaX}yXown!AufR7+0~| z4VCq(fjP`Gw4*|2bC)CYRpqx};JP|{+>tH&OsXR;8n~g(7yoEFa=)&YmJBSbCC#k2 ztoD9gMMeaY2UeqPx?M*K1la;dEC+-YTWO~x5Z$xu44JA}ZTY&}I+o6%dEDg6v{#m@ z=~&9{Ek@lFt0S;n`A@x>ILSi2>(zXEq+Fgh9axUO!%VO!-hRHyBOdiHE%h%tJLHvg zPwe_z(=l7pl@75Czi|Deir~FhH(#tj*N*&Z4g&fcIs=~jRTa>QH!u=My=n_g_#(rt za;@2GO#Q&_IyL#yQuRv(+HXTO1+Oi^CI=!|P+bdwRa#@XNt?GkV)Kdv_BiK!7W}R; zqR3Hjj1?{*zIZ8a@vF9hC~otsg6V)9@*I;W;0{+*@QSws=wG3oW8xQPK66!Im|>j$ zcdNWnh9(W5V*%*OwdsB_Xq5&J$cQOzoxSJ+J3ef zI;I)$AdEK?&O1;4hhe;#Fy0J#7e{zEgS?v_@1rnY%3tDLqT@34x59X{;k;|~e;me} z4dcy|w=lxH9pv5ic%OvvQvMR}IvqFIhEE3pyWTAV*&mqvaDkO?&<3;2V3r+T6#s3g Q8H3IgX~GGVXpf=%7fh!EL;wH) 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 index 8a3312c..4c62ec2 100644 --- 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 @@ -38,20 +38,17 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // 这是配置的关键,决定哪些接口开启防护,哪些接口绕过防护 - http - // 关闭csrf跨站请求伪造 - .csrf().disable() - // 开启跨域以便前端调用接口 - .cors().and() + http.csrf().disable() // 关闭csrf跨站请求伪造 + .cors().and()// 开启跨域以便前端调用接口 .authorizeRequests() // 指定某些接口不需要通过验证即可访问。登陆接口肯定是不需要认证的 - //.antMatchers("/admin/system/index/login").permitAll() + .antMatchers("/admin/system/index/login").permitAll() // 这里意思是其它所有接口需要认证才能访问 .anyRequest().authenticated() .and() - // TokenAuthenticationFilter放到UsernamePasswordAuthenticationFilter的前面,这样做就是为了除了登录的时候去查询数据库外,其他时候都用token进行认证。 - .addFilterBefore(new TokenAuthenticationFilter(redisTemplate), - UsernamePasswordAuthenticationFilter.class) + // TokenAuthenticationFilter放到UsernamePasswordAuthenticationFilter的前面 + // 这样做就是为了除了登录的时候去查询数据库外,其他时候都用token进行认证。 + .addFilterBefore(new TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class) .addFilter(new TokenLoginFilter(authenticationManager(), redisTemplate)); // 禁用session 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 index 1969f79..3c752ed 100644 --- 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 @@ -11,7 +11,6 @@ import java.util.Collection; @Setter @Getter public class CustomUser extends User { - /** * 我们自己的用户实体对象,要调取用户信息时直接获取这个实体对象。(这里我就不写get/set方法了) */ @@ -21,5 +20,4 @@ public class CustomUser extends User { super(sysUser.getUsername(), sysUser.getPassword(), authorities); this.sysUser = sysUser; } - } 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 index e851f99..448bff0 100644 --- 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 @@ -3,9 +3,9 @@ package com.atguigu.security.filter; import com.alibaba.fastjson.JSON; import com.atguigu.common.result.Result; import com.atguigu.common.result.ResultCodeEnum; +import com.atguigu.common.utlis.BaseContext; import com.atguigu.common.utlis.JwtHelper; import com.atguigu.common.utlis.ResponseUtil; -import com.atguigu.security.custom.LoginUserInfoHelper; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -56,8 +56,8 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { String username = JwtHelper.getUserName(token); if (!StringUtils.isEmpty(username)) { // 当前用户信息放到ThreadLocal里面 - LoginUserInfoHelper.setUserId(JwtHelper.getUserId(token)); - LoginUserInfoHelper.setUsername(username); + BaseContext.setUserId(JwtHelper.getUserId(token)); + BaseContext.setUsername(username); // 通过username从redis获取权限数据 String authString = (String) redisTemplate.opsForValue().get(username); 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/service/UserDetailsService.java similarity index 93% rename from common/spring-security/src/main/java/com/atguigu/security/custom/UserDetailsService.java rename to common/spring-security/src/main/java/com/atguigu/security/service/UserDetailsService.java index e0057c4..9185009 100644 --- a/common/spring-security/src/main/java/com/atguigu/security/custom/UserDetailsService.java +++ b/common/spring-security/src/main/java/com/atguigu/security/service/UserDetailsService.java @@ -1,4 +1,4 @@ -package com.atguigu.security.custom; +package com.atguigu.security.service; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; 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 index 64460ad..dcea726 100644 --- 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 @@ -5,9 +5,9 @@ import com.atguigu.constant.MessageConstant; import com.atguigu.exception.BunnyException; import com.atguigu.model.system.SysUser; import com.atguigu.security.custom.CustomUser; +import com.atguigu.security.service.UserDetailsService; 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.stereotype.Component; diff --git a/service-oa/target/classes/application-dev.yml b/service-oa/target/classes/application-dev.yml deleted file mode 100644 index 2ea6574..0000000 --- a/service-oa/target/classes/application-dev.yml +++ /dev/null @@ -1,21 +0,0 @@ -server: - port: 8800 - -bunny: - datasource: - host: 106.15.251.123 - port: 3305 - sqlData: guigu-oa - username: root - password: "02120212" - -# nacos: -# server-addr: z-bunny.cn:8848 -# discovery: -# namespace: ssyx -# -# minio: -# endpointUrl: "http://129.211.31.58:9000" -# bucket-name: ssyx -# accessKey: bunny -# secretKey: "02120212" \ No newline at end of file diff --git a/service-oa/target/classes/application.yml b/service-oa/target/classes/application.yml deleted file mode 100644 index 856c064..0000000 --- a/service-oa/target/classes/application.yml +++ /dev/null @@ -1,34 +0,0 @@ -server: - port: 8800 - -spring: - application: - name: service-oa - profiles: - active: dev - - datasource: - type: com.zaxxer.hikari.HikariDataSource - driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://${bunny.datasource.host}:${bunny.datasource.port}/${bunny.datasource.sqlData}?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true - username: ${bunny.datasource.username} - password: ${bunny.datasource.password} - - jackson: - date-format: yyyy-MM-dd HH:mm:ss - time-zone: GMT+8 - -mybatis-plus: - mapper-locations: classpath:mapper/*.xml - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 查看日志 - -logging: - level: - com.atguigu.auth.mapper: debug - com.atguigu.auth.controller: info - com.atguigu.auth.service: info - pattern: - dateformat: HH:mm:ss:SSS - file: - path: "logs/${spring.application.name}" \ No newline at end of file diff --git a/service-oa/target/classes/banner.txt b/service-oa/target/classes/banner.txt deleted file mode 100644 index cc77fc2..0000000 --- a/service-oa/target/classes/banner.txt +++ /dev/null @@ -1,16 +0,0 @@ ------------------▄██-█▄--------- ------------------███▄██▄-------- ------------------███████-------- ------------------▀███████------- --------------------██████▄▄----- --------------------█████████▄--- --------------------██████▄████-- --------▄███████████████████████- ------▄███████████████████████▀-- ----▄██████████████████████------ ----███████████████████████------ ----███████████████████████------ --▄▄██████████████████████▀------ --█████████████████▀█████-------- --▀██████████████▀▀-▀█████▄------ --------▀▀▀▀▀▀▀▀▀------▀▀▀▀------ \ No newline at end of file diff --git a/service-oa/target/classes/favicon.ico b/service-oa/target/classes/favicon.ico deleted file mode 100644 index 2f64da52ae22180ce73a6cda8d6724f8ad91a185..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17014 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