Skip to content

Commit ce1a8f1

Browse files
committed
springboot 学习 之 spring security 权限控制
1 parent a198f79 commit ce1a8f1

File tree

16 files changed

+646
-0
lines changed

16 files changed

+646
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>springboot_security</artifactId>
7+
<groupId>com.zjh</groupId>
8+
<version>0.0.1-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>05_role_permission</artifactId>
13+
14+
<dependencies>
15+
<dependency>
16+
<groupId>org.springframework.boot</groupId>
17+
<artifactId>spring-boot-starter-jdbc</artifactId>
18+
</dependency>
19+
<dependency>
20+
<groupId>mysql</groupId>
21+
<artifactId>mysql-connector-java</artifactId>
22+
</dependency>
23+
24+
<!-- https://mvnrepository.com/artifact/org.springframework.session/spring-session -->
25+
<dependency>
26+
<groupId>org.springframework.social</groupId>
27+
<artifactId>spring-social-config</artifactId>
28+
<version>1.1.6.RELEASE</version>
29+
</dependency>
30+
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
31+
<dependency>
32+
<groupId>org.apache.commons</groupId>
33+
<artifactId>commons-lang3</artifactId>
34+
<version>3.10</version>
35+
</dependency>
36+
</dependencies>
37+
38+
39+
</project>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.zjh.security;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
/**
7+
* @author zjh on 2020/7/6
8+
*/
9+
@SpringBootApplication
10+
public class PermissionApplication {
11+
public static void main(String[] args) {
12+
SpringApplication.run(PermissionApplication.class);
13+
}
14+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.zjh.security.captcha;
2+
3+
import java.awt.image.BufferedImage;
4+
import java.time.LocalDateTime;
5+
6+
/**
7+
* @author zjh on 2020/7/6
8+
*/
9+
public class ImageCode {
10+
11+
private BufferedImage image;
12+
13+
private String code;
14+
15+
private LocalDateTime expireTime;
16+
17+
public ImageCode(BufferedImage image, String code, int expireIn) {
18+
this.image = image;
19+
this.code = code;
20+
this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
21+
}
22+
// image图片 code验证码 expireTime过期时间
23+
public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) {
24+
this.image = image;
25+
this.code = code;
26+
this.expireTime = expireTime;
27+
}
28+
// 过期时间
29+
public boolean isExpire() {
30+
return LocalDateTime.now().isAfter(expireTime);
31+
}
32+
33+
public BufferedImage getImage() {
34+
return image;
35+
}
36+
37+
public void setImage(BufferedImage image) {
38+
this.image = image;
39+
}
40+
41+
public String getCode() {
42+
return code;
43+
}
44+
45+
public void setCode(String code) {
46+
this.code = code;
47+
}
48+
49+
public LocalDateTime getExpireTime() {
50+
return expireTime;
51+
}
52+
53+
public void setExpireTime(LocalDateTime expireTime) {
54+
this.expireTime = expireTime;
55+
}
56+
57+
@Override
58+
public String toString() {
59+
return "ImageCode{" +
60+
"image=" + image +
61+
", code='" + code + '\'' +
62+
", expireTime=" + expireTime +
63+
'}';
64+
}
65+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.zjh.security.config;
2+
3+
4+
import com.zjh.security.fileter.ValidateCodeFilter;
5+
import com.zjh.security.handler.MyAuthenticationAccessDeniedHandler;
6+
import com.zjh.security.handler.MyAuthenticationFailureHandler;
7+
import com.zjh.security.handler.MyAuthenticationSuccessHandler;
8+
import com.zjh.security.service.UserDetailService;
9+
import org.springframework.beans.factory.annotation.Autowired;
10+
import org.springframework.context.annotation.Bean;
11+
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
12+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
13+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
14+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
15+
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
16+
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
17+
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
18+
import org.springframework.stereotype.Component;
19+
20+
import javax.sql.DataSource;
21+
22+
/**
23+
* @author zjh on 2020/7/5
24+
*/
25+
@Component
26+
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启权限注解
27+
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
28+
@Autowired
29+
private MyAuthenticationFailureHandler authenticationFailureHandler;
30+
31+
@Autowired
32+
private MyAuthenticationSuccessHandler authenticationSuccessHandler;
33+
@Autowired
34+
private ValidateCodeFilter validateCodeFilter;
35+
@Autowired
36+
private UserDetailService userDetailService;
37+
@Autowired
38+
private DataSource dataSource;
39+
@Autowired
40+
private MyAuthenticationAccessDeniedHandler myAuthenticationAccessDeniedHandler;
41+
42+
public PersistentTokenRepository persistentTokenRepository() {
43+
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
44+
jdbcTokenRepository.setDataSource(dataSource);
45+
jdbcTokenRepository.setCreateTableOnStartup(false);
46+
return jdbcTokenRepository;
47+
}
48+
@Bean
49+
public BCryptPasswordEncoder bCryptPasswordEncoder(){
50+
return new BCryptPasswordEncoder();
51+
}
52+
@Override
53+
protected void configure(HttpSecurity http) throws Exception {
54+
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器
55+
.exceptionHandling()
56+
.accessDeniedHandler(myAuthenticationAccessDeniedHandler)
57+
.and()
58+
.formLogin() // 表单登录
59+
// http.httpBasic() // HTTP Basic
60+
.loginPage("/authentication/require") // 登录跳转 URL
61+
.loginProcessingUrl("/login") // 处理表单登录 URL
62+
.failureHandler(authenticationFailureHandler) // 处理登录失败
63+
.successHandler(authenticationSuccessHandler)
64+
.and()
65+
.rememberMe() // 启用rememberMe
66+
.tokenRepository(persistentTokenRepository()) // 配置 token 持久化仓库
67+
.tokenValiditySeconds(3600) // remember 过期时间,单为秒
68+
.userDetailsService(userDetailService) // 处理自动登录逻辑
69+
.and()
70+
.authorizeRequests() // 授权配置
71+
.antMatchers("/authentication/require",
72+
"/login.html",
73+
"/code/image").permitAll() // 无需认证的请求路径
74+
.anyRequest() // 所有请求
75+
.authenticated() // 都需要认证
76+
.and().csrf().disable();
77+
}
78+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.zjh.security.controller;
2+
3+
import org.springframework.security.access.prepost.PreAuthorize;
4+
import org.springframework.security.core.context.SecurityContextHolder;
5+
import org.springframework.web.bind.annotation.GetMapping;
6+
import org.springframework.web.bind.annotation.RestController;
7+
8+
@RestController
9+
public class IndexController {
10+
@GetMapping("index")
11+
public Object index(){
12+
return SecurityContextHolder.getContext().getAuthentication();
13+
}
14+
@GetMapping("/auth/admin")
15+
@PreAuthorize("hasAuthority('admin')")
16+
public String authenticationTest() {
17+
return "您拥有admin权限,可以查看";
18+
}
19+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.zjh.security.controller;
2+
3+
import org.springframework.http.HttpStatus;
4+
import org.springframework.security.web.DefaultRedirectStrategy;
5+
import org.springframework.security.web.RedirectStrategy;
6+
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
7+
import org.springframework.security.web.savedrequest.RequestCache;
8+
import org.springframework.security.web.savedrequest.SavedRequest;
9+
import org.springframework.util.StringUtils;
10+
import org.springframework.web.bind.annotation.GetMapping;
11+
import org.springframework.web.bind.annotation.ResponseStatus;
12+
import org.springframework.web.bind.annotation.RestController;
13+
14+
import javax.servlet.http.HttpServletRequest;
15+
import javax.servlet.http.HttpServletResponse;
16+
import java.io.IOException;
17+
18+
@RestController
19+
public class MySecurityController {
20+
//RequestCache requestCache是Spring Security提供的用于缓存请求的对象
21+
private RequestCache requestCache = new HttpSessionRequestCache();
22+
//DefaultRedirectStrategy是Spring Security提供的重定向策略
23+
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
24+
25+
@GetMapping("/authentication/require")
26+
@ResponseStatus(HttpStatus.UNAUTHORIZED)
27+
public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {
28+
//getRequest方法可以获取到本次请求的HTTP信息
29+
SavedRequest savedRequest = requestCache.getRequest(request, response);
30+
if (savedRequest != null) {
31+
String targetUrl = savedRequest.getRedirectUrl();
32+
if (StringUtils.endsWithIgnoreCase(targetUrl, ".html"))
33+
//sendRedirect为Spring Security提供的用于处理重定向的方法
34+
redirectStrategy.sendRedirect(request, response, "/login.html");
35+
}
36+
return "访问的资源需要身份认证!";
37+
}
38+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.zjh.security.controller;
2+
3+
import com.zjh.security.captcha.ImageCode;
4+
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
5+
import org.springframework.social.connect.web.SessionStrategy;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.RestController;
8+
import org.springframework.web.context.request.ServletWebRequest;
9+
10+
import javax.imageio.ImageIO;
11+
import javax.servlet.http.HttpServletRequest;
12+
import javax.servlet.http.HttpServletResponse;
13+
import java.awt.*;
14+
import java.awt.image.BufferedImage;
15+
import java.io.IOException;
16+
import java.util.Random;
17+
18+
@RestController
19+
public class ValidateController {
20+
21+
public final static String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";
22+
23+
private final SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
24+
25+
26+
27+
@GetMapping("/code/image")
28+
public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
29+
ImageCode imageCode = createImageCode();
30+
sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY, imageCode);
31+
ImageIO.write(imageCode.getImage(), "jpeg", response.getOutputStream());
32+
33+
System.out.println(imageCode);
34+
}
35+
36+
private ImageCode createImageCode() {
37+
// 该参数可以自定义
38+
int width = 100; // 验证码图片宽度
39+
int height = 36; // 验证码图片长度
40+
int length = 4; // 验证码位数
41+
int expireIn = 60; // 验证码有效时间 60s
42+
43+
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
44+
Graphics g = image.getGraphics();
45+
46+
Random random = new Random();
47+
48+
g.setColor(getRandColor(200, 250));
49+
g.fillRect(0, 0, width, height);
50+
g.setFont(new Font("Times New Roman", Font.ITALIC, 20));
51+
g.setColor(getRandColor(160, 200));
52+
for (int i = 0; i < 155; i++) {
53+
int x = random.nextInt(width);
54+
int y = random.nextInt(height);
55+
int xl = random.nextInt(12);
56+
int yl = random.nextInt(12);
57+
g.drawLine(x, y, x + xl, y + yl);
58+
}
59+
60+
StringBuilder sRand = new StringBuilder();
61+
for (int i = 0; i < length; i++) {
62+
String rand = String.valueOf(random.nextInt(10));
63+
sRand.append(rand);
64+
g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
65+
g.drawString(rand, 13 * i + 6, 16);
66+
}
67+
g.dispose();
68+
return new ImageCode(image, sRand.toString(), expireIn);
69+
}
70+
71+
private Color getRandColor(int fc, int bc) {
72+
Random random = new Random();
73+
if (fc > 255) {
74+
fc = 255;
75+
}
76+
if (bc > 255) {
77+
bc = 255;
78+
}
79+
int r = fc + random.nextInt(bc - fc);
80+
int g = fc + random.nextInt(bc - fc);
81+
int b = fc + random.nextInt(bc - fc);
82+
return new Color(r, g, b);
83+
}
84+
}

0 commit comments

Comments
 (0)