Skip to content

Commit 938ae1f

Browse files
committed
自定义权限校验,增加匿名访问注解,扩展PreAuthorize 匿名注解
1 parent c9c86f0 commit 938ae1f

6 files changed

Lines changed: 63 additions & 19 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package me.zhengjie.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
/**
9+
* @author jacky
10+
* 用于标记匿名访问方法
11+
*/
12+
@Target(ElementType.METHOD)
13+
@Retention(RetentionPolicy.RUNTIME)
14+
public @interface AnonymousAccess {
15+
16+
}

eladmin-common/src/main/java/me/zhengjie/config/ElPermissionConfig.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package me.zhengjie.config;
22

33
import me.zhengjie.utils.SecurityUtils;
4+
import org.springframework.beans.factory.annotation.Value;
45
import org.springframework.security.core.GrantedAuthority;
56
import org.springframework.stereotype.Service;
67
import java.util.Arrays;
@@ -11,6 +12,11 @@
1112
public class ElPermissionConfig {
1213

1314
public Boolean check(String ...permissions){
15+
// 如果是匿名访问的,就放行
16+
String anonymous = "anonymous";
17+
if(Arrays.asList(permissions).contains(anonymous)){
18+
return true;
19+
}
1420
List<String> elPermissions = SecurityUtils.getUserDetails().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
1521
List<String> list = Arrays.stream(permissions).filter(elPermissions::contains).map(s -> s).collect(Collectors.toList());
1622
if(elPermissions.contains("admin") || list.size() != 0){

eladmin-system/src/main/java/me/zhengjie/modules/monitor/rest/LimitController.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import io.swagger.annotations.Api;
44
import io.swagger.annotations.ApiOperation;
5+
import me.zhengjie.annotation.AnonymousAccess;
56
import me.zhengjie.annotation.Limit;
7+
import org.springframework.security.access.prepost.PreAuthorize;
68
import org.springframework.web.bind.annotation.GetMapping;
79
import org.springframework.web.bind.annotation.RequestMapping;
810
import org.springframework.web.bind.annotation.RestController;
@@ -17,12 +19,14 @@
1719
@RequestMapping("/api/limit")
1820
@Api(tags = "系统:限流测试管理")
1921
public class LimitController {
22+
2023
private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger();
2124

2225
/**
2326
* 测试限流注解,下面配置说明该接口 60秒内最多只能访问 10次,保存到redis的键名为 limit_test,
2427
*/
2528
@GetMapping
29+
@PreAuthorize("@el.check('anonymous')")
2630
@ApiOperation("测试")
2731
@Limit(key = "test", period = 60, count = 10, name = "testLimit", prefix = "limit")
2832
public int testLimit() {

eladmin-system/src/main/java/me/zhengjie/modules/security/config/SecurityConfig.java

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package me.zhengjie.modules.security.config;
22

3+
import me.zhengjie.annotation.AnonymousAccess;
4+
import me.zhengjie.config.ElPermissionConfig;
35
import me.zhengjie.modules.security.security.JwtAuthenticationEntryPoint;
46
import me.zhengjie.modules.security.security.JwtAuthorizationTokenFilter;
57
import me.zhengjie.modules.security.service.JwtUserDetailsService;
68
import org.springframework.beans.factory.annotation.Autowired;
79
import org.springframework.beans.factory.annotation.Value;
10+
import org.springframework.context.ApplicationContext;
811
import org.springframework.context.annotation.Bean;
912
import org.springframework.context.annotation.Configuration;
1013
import org.springframework.http.HttpMethod;
14+
import org.springframework.security.access.prepost.PreAuthorize;
1115
import org.springframework.security.authentication.AuthenticationManager;
1216
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
1317
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@@ -19,6 +23,13 @@
1923
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
2024
import org.springframework.security.crypto.password.PasswordEncoder;
2125
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
26+
import org.springframework.web.method.HandlerMethod;
27+
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
28+
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
29+
30+
import java.util.HashSet;
31+
import java.util.Map;
32+
import java.util.Set;
2233

2334
@Configuration
2435
@EnableWebSecurity
@@ -29,16 +40,19 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
2940

3041
private final JwtUserDetailsService jwtUserDetailsService;
3142

43+
private final ApplicationContext applicationContext;
44+
3245
// 自定义基于JWT的安全过滤器
3346
private final JwtAuthorizationTokenFilter authenticationTokenFilter;
3447

3548
@Value("${jwt.header}")
3649
private String tokenHeader;
3750

38-
public SecurityConfig(JwtAuthenticationEntryPoint unauthorizedHandler, JwtUserDetailsService jwtUserDetailsService, JwtAuthorizationTokenFilter authenticationTokenFilter) {
51+
public SecurityConfig(JwtAuthenticationEntryPoint unauthorizedHandler, JwtUserDetailsService jwtUserDetailsService, JwtAuthorizationTokenFilter authenticationTokenFilter, ApplicationContext applicationContext) {
3952
this.unauthorizedHandler = unauthorizedHandler;
4053
this.jwtUserDetailsService = jwtUserDetailsService;
4154
this.authenticationTokenFilter = authenticationTokenFilter;
55+
this.applicationContext = applicationContext;
4256
}
4357

4458
@Autowired
@@ -67,18 +81,26 @@ public AuthenticationManager authenticationManagerBean() throws Exception {
6781

6882
@Override
6983
protected void configure(HttpSecurity httpSecurity) throws Exception {
70-
84+
// 搜寻 匿名标记 url: PreAuthorize("hasAnyRole('anonymous')") 和 PreAuthorize("@el.check('anonymous')") 和 AnonymousAccess
85+
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
86+
Set<String> anonymousUrls = new HashSet<>();
87+
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
88+
HandlerMethod handlerMethod = infoEntry.getValue();
89+
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
90+
PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);
91+
if (null != preAuthorize && preAuthorize.value().contains("anonymous")) {
92+
anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
93+
} else if (null != anonymousAccess && null == preAuthorize) {
94+
anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
95+
}
96+
}
7197
httpSecurity
72-
7398
// 禁用 CSRF
7499
.csrf().disable()
75-
76100
// 授权异常
77101
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
78-
79102
// 不创建会话
80103
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
81-
82104
// 过滤请求
83105
.authorizeRequests()
84106
.antMatchers(
@@ -88,31 +110,20 @@ protected void configure(HttpSecurity httpSecurity) throws Exception {
88110
"/**/*.css",
89111
"/**/*.js"
90112
).anonymous()
91-
92-
.antMatchers(HttpMethod.POST,"/auth/login").permitAll()
93-
.antMatchers(HttpMethod.DELETE,"/auth/logout").permitAll()
94-
.antMatchers(HttpMethod.GET,"/auth/code").permitAll()
95-
// 支付宝回调
96-
.antMatchers("/api/aliPay/return").permitAll()
97-
.antMatchers("/api/aliPay/notify").permitAll()
98-
99113
// swagger start
100114
.antMatchers("/swagger-ui.html").permitAll()
101115
.antMatchers("/swagger-resources/**").permitAll()
102116
.antMatchers("/webjars/**").permitAll()
103117
.antMatchers("/*/api-docs").permitAll()
104118
// swagger end
105-
106-
// 接口限流测试
107-
.antMatchers("/test/**").permitAll()
108119
// 文件
109120
.antMatchers("/avatar/**").permitAll()
110121
.antMatchers("/file/**").permitAll()
111-
112122
// 放行OPTIONS请求
113123
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
114-
115124
.antMatchers("/druid/**").permitAll()
125+
// 自定义匿名访问所有url放行 : 允许 匿名和带权限以及登录用户访问
126+
.antMatchers(anonymousUrls.toArray(new String[0])).permitAll()
116127
// 所有请求都需要认证
117128
.anyRequest().authenticated()
118129
// 防止iframe 造成跨域

eladmin-system/src/main/java/me/zhengjie/modules/security/rest/AuthenticationController.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import io.swagger.annotations.Api;
66
import io.swagger.annotations.ApiOperation;
77
import lombok.extern.slf4j.Slf4j;
8+
import me.zhengjie.annotation.AnonymousAccess;
89
import me.zhengjie.aop.log.Log;
910
import me.zhengjie.exception.BadRequestException;
1011
import me.zhengjie.modules.monitor.service.RedisService;
@@ -58,6 +59,7 @@ public AuthenticationController(JwtTokenUtil jwtTokenUtil, RedisService redisSer
5859

5960
@Log("用户登录")
6061
@ApiOperation("登录授权")
62+
@AnonymousAccess
6163
@PostMapping(value = "/login")
6264
public ResponseEntity login(@Validated @RequestBody AuthUser authorizationUser, HttpServletRequest request){
6365

@@ -96,6 +98,7 @@ public ResponseEntity getUserInfo(){
9698
}
9799

98100
@ApiOperation("获取验证码")
101+
@AnonymousAccess
99102
@GetMapping(value = "/code")
100103
public ImgResult getCode(){
101104
// 算术类型 https://gitee.com/whvse/EasyCaptcha
@@ -110,6 +113,7 @@ public ImgResult getCode(){
110113
}
111114

112115
@ApiOperation("退出登录")
116+
@AnonymousAccess
113117
@DeleteMapping(value = "/logout")
114118
public ResponseEntity logout(HttpServletRequest request){
115119
onlineUserService.logout(jwtTokenUtil.getToken(request));

eladmin-tools/src/main/java/me/zhengjie/rest/AliPayController.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.swagger.annotations.Api;
44
import io.swagger.annotations.ApiOperation;
55
import lombok.extern.slf4j.Slf4j;
6+
import me.zhengjie.annotation.AnonymousAccess;
67
import me.zhengjie.aop.log.Log;
78
import me.zhengjie.domain.AlipayConfig;
89
import me.zhengjie.domain.vo.TradeVo;
@@ -74,6 +75,7 @@ public ResponseEntity<String> toPayAsWeb(@Validated @RequestBody TradeVo trade)
7475

7576
@ApiIgnore
7677
@GetMapping("/return")
78+
@AnonymousAccess
7779
@ApiOperation("支付之后跳转的链接")
7880
public ResponseEntity<String> returnPage(HttpServletRequest request, HttpServletResponse response){
7981
AlipayConfig alipay = alipayService.find();
@@ -96,6 +98,7 @@ public ResponseEntity<String> returnPage(HttpServletRequest request, HttpServlet
9698

9799
@ApiIgnore
98100
@RequestMapping("/notify")
101+
@AnonymousAccess
99102
@ApiOperation("支付异步通知(要公网访问),接收异步通知,检查通知内容app_id、out_trade_no、total_amount是否与请求中的一致,根据trade_status进行后续业务处理")
100103
public ResponseEntity notify(HttpServletRequest request){
101104
AlipayConfig alipay = alipayService.find();

0 commit comments

Comments
 (0)