以下框架为Springboot2.x版本,使用数据库为MySQL,使用Spring的Security而搭建出来的WEB项目,此项目是模仿Springboot-Security-SHADOW,这里仅显示主要的核心代码,全部内容在底部Github链接。

1.CsrfSecurityRequestMatcher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.regex.Pattern;

public class CsrfSecurityRequestMatcher implements RequestMatcher {
protected Log log = LogFactory.getLog(getClass());
private Pattern allowedMethods = Pattern
.compile("^(GET|HEAD|TRACE|OPTIONS)$");
/**
* 需要排除的url列表
*/
private List<String> execludeUrls;

@Override
public boolean matches(HttpServletRequest request) {
if (execludeUrls != null && execludeUrls.size() > 0) {
String servletPath = request.getServletPath();
for (String url : execludeUrls) {
if (servletPath.contains(url)) {
log.info("++++"+servletPath);
return false;
}
}
}
return !allowedMethods.matcher(request.getMethod()).matches();
}

public List<String> getExecludeUrls() {
return execludeUrls;
}

public void setExecludeUrls(List<String> execludeUrls) {
this.execludeUrls = execludeUrls;
}
}

2.CustomAccessDecisionManager

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;
import java.util.Iterator;

public class CustomAccessDecisionManager implements AccessDecisionManager {

protected Log logger = LogFactory.getLog(getClass());
@Override
public void decide(Authentication authentication, Object object,
Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
if (configAttributes == null) {
return;
}

//config urlroles
Iterator<ConfigAttribute> iterator = configAttributes.iterator();

while (iterator.hasNext()) {
ConfigAttribute configAttribute = iterator.next();
//need role
String needRole = configAttribute.getAttribute();
//user roles
for (GrantedAuthority ga : authentication.getAuthorities()) {
if (needRole.equals(ga.getAuthority())) {
return;
}
}
logger.info("need role is " + needRole);
}
throw new AccessDeniedException("Cannot Access!");
}

@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}

@Override
public boolean supports(Class<?> clazz) {
return true;
}

}

3.CustomFilterSecurityInterceptor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import javax.servlet.*;
import java.io.IOException;

public class CustomFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
protected Log logger = LogFactory.getLog(getClass());
// private static final Logger logger = Logger.getLogger(CustomFilterSecurityInterceptor.class);
private FilterInvocationSecurityMetadataSource securityMetadataSource;

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
logger.debug("===="+fi.getRequestUrl());
invoke(fi);
}

public void invoke(FilterInvocation fi) throws IOException, ServletException {
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} catch (Exception e) {
logger.error(e.getMessage());
} finally {
super.afterInvocation(token, null);
}
}

public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return this.securityMetadataSource;
}

@Override
public Class<? extends Object> getSecureObjectClass() {
return FilterInvocation.class;
}

@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}

public void setSecurityMetadataSource(
FilterInvocationSecurityMetadataSource smSource) {
this.securityMetadataSource = smSource;
}

@Override
public void destroy() {
// TODO Auto-generated method stub
}

@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}

}

4.CustomSecurityMetadataSource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import java.util.*;

public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
protected Log logger = LogFactory.getLog(getClass());

private Map<String, Collection<ConfigAttribute>> resourceMap = null;
private PathMatcher pathMatcher = new AntPathMatcher();

private String urlroles;

@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}

public CustomSecurityMetadataSource(String urlroles) {
super();
this.urlroles = urlroles;
resourceMap = loadResourceMatchAuthority();
}

private Map<String, Collection<ConfigAttribute>> loadResourceMatchAuthority() {

Map<String, Collection<ConfigAttribute>> map = new HashMap<String, Collection<ConfigAttribute>>();

if (urlroles != null && !urlroles.isEmpty()) {
String[] resouces = urlroles.split(";");
for (String resource : resouces) {
String[] urls = resource.split("=");
String[] roles = urls[1].split(",");
Collection<ConfigAttribute> list = new ArrayList<ConfigAttribute>();
for (String role : roles) {
ConfigAttribute config = new SecurityConfig(role.trim());
list.add(config);
}
//key:url, value:roles
map.put(urls[0].trim(), list);
}
} else {
logger.error("'securityconfig.urlroles' must be set");
}

logger.info("Loaded UrlRoles Resources.");
return map;

}

@Override
public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
String url = ((FilterInvocation) object).getRequestUrl();

logger.debug("request url is " + url);

if (resourceMap == null) {
resourceMap = loadResourceMatchAuthority();
}

Iterator<String> ite = resourceMap.keySet().iterator();
while (ite.hasNext()) {
String resURL = ite.next();
if (pathMatcher.match(resURL, url)) {
return resourceMap.get(resURL);
}
}
return resourceMap.get(url);
}

@Override
public boolean supports(Class<?> clazz) {
return true;
}
}

5.CustomSecurityMetadataSource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import java.util.*;

public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
protected Log logger = LogFactory.getLog(getClass());

private Map<String, Collection<ConfigAttribute>> resourceMap = null;
private PathMatcher pathMatcher = new AntPathMatcher();

private String urlroles;

@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}

public CustomSecurityMetadataSource(String urlroles) {
super();
this.urlroles = urlroles;
resourceMap = loadResourceMatchAuthority();
}

private Map<String, Collection<ConfigAttribute>> loadResourceMatchAuthority() {

Map<String, Collection<ConfigAttribute>> map = new HashMap<String, Collection<ConfigAttribute>>();

if (urlroles != null && !urlroles.isEmpty()) {
String[] resouces = urlroles.split(";");
for (String resource : resouces) {
String[] urls = resource.split("=");
String[] roles = urls[1].split(",");
Collection<ConfigAttribute> list = new ArrayList<ConfigAttribute>();
for (String role : roles) {
ConfigAttribute config = new SecurityConfig(role.trim());
list.add(config);
}
//key:url, value:roles
map.put(urls[0].trim(), list);
}
} else {
logger.error("'securityconfig.urlroles' must be set");
}

logger.info("Loaded UrlRoles Resources.");
return map;

}

@Override
public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
String url = ((FilterInvocation) object).getRequestUrl();

logger.debug("request url is " + url);

if (resourceMap == null) {
resourceMap = loadResourceMatchAuthority();
}

Iterator<String> ite = resourceMap.keySet().iterator();
while (ite.hasNext()) {
String resURL = ite.next();
if (pathMatcher.match(resURL, url)) {
return resourceMap.get(resURL);
}
}
return resourceMap.get(url);
}

@Override
public boolean supports(Class<?> clazz) {
return true;
}
}

6.SecurityConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import com.chanchifeng.web.service.CustomUserDetailsService;
import com.chanchifeng.web.service.LoginSuccessHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

@Configuration
//@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@Order(SecurityProperties.BASIC_AUTH_ORDER)
@EnableConfigurationProperties(SecuritySettings.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
protected Log log = LogFactory.getLog(getClass());
// @Autowired
// private AuthenticationManager authenticationManager;
@Autowired
private SecuritySettings settings;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
@Qualifier("dataSource")
private DataSource dataSource;

@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
//remember meauthenticationManager
auth.eraseCredentials(false);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().loginPage("/login").permitAll().successHandler(loginSuccessHandler())
.and().authorizeRequests()
.antMatchers("/images/**", "/checkcode", "/scripts/**", "/styles/**").permitAll()
.antMatchers(settings.getPermitall().split(",")).permitAll()
.anyRequest().authenticated()
.and().csrf().requireCsrfProtectionMatcher(csrfSecurityRequestMatcher())
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and().logout().logoutSuccessUrl(settings.getLogoutsuccssurl())
.and().exceptionHandling().accessDeniedPage(settings.getDeniedpage())
.and().rememberMe().tokenValiditySeconds(86400).tokenRepository(tokenRepository());
}

@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public JdbcTokenRepositoryImpl tokenRepository() {
JdbcTokenRepositoryImpl jtr = new JdbcTokenRepositoryImpl();
jtr.setDataSource(dataSource);
return jtr;
}

@Bean
public LoginSuccessHandler loginSuccessHandler() {
return new LoginSuccessHandler();
}

@Bean
public CustomFilterSecurityInterceptor customFilter() throws Exception {
CustomFilterSecurityInterceptor customFilter = new CustomFilterSecurityInterceptor();
customFilter.setSecurityMetadataSource(securityMetadataSource());
customFilter.setAccessDecisionManager(accessDecisionManager());
// customFilter.setAuthenticationManager(authenticationManager);
return customFilter;
}

@Bean
public CustomAccessDecisionManager accessDecisionManager() {
return new CustomAccessDecisionManager();
}

@Bean
public CustomSecurityMetadataSource securityMetadataSource() {
return new CustomSecurityMetadataSource(settings.getUrlroles());
}


private CsrfSecurityRequestMatcher csrfSecurityRequestMatcher() {
CsrfSecurityRequestMatcher csrfSecurityRequestMatcher = new CsrfSecurityRequestMatcher();
List<String> list = new ArrayList<String>();
list.add("/rest/");
csrfSecurityRequestMatcher.setExecludeUrls(list);
return csrfSecurityRequestMatcher;
}
}

7.SecuritySettings

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix="securityconfig")
public class SecuritySettings {
private String logoutsuccssurl = "/logout";
private String permitall = "/api";
private String deniedpage = "/deny";
private String urlroles;

public String getLogoutsuccssurl() {
return logoutsuccssurl;
}

public void setLogoutsuccssurl(String logoutsuccssurl) {
this.logoutsuccssurl = logoutsuccssurl;
}

public String getPermitall() {
return permitall;
}

public void setPermitall(String permitall) {
this.permitall = permitall;
}

public String getDeniedpage() {
return deniedpage;
}

public void setDeniedpage(String deniedpage) {
this.deniedpage = deniedpage;
}

public String getUrlroles() {
return urlroles;
}

public void setUrlroles(String urlroles) {
this.urlroles = urlroles;
}
}

8.LoginController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import com.chanchifeng.web.service.ImageCode;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Map;

@Controller
public class LoginController {
@RequestMapping("/login")
public String login() {
return "login";
}


@RequestMapping(value = "/images/imagecode")
public String imagecode(HttpServletRequest request, HttpServletResponse response)
throws Exception {
OutputStream os = response.getOutputStream();
Map<String, Object> map = ImageCode.getImageCode(60, 20, os);

String simpleCaptcha = "simpleCaptcha";
request.getSession().setAttribute(simpleCaptcha, map.get("strEnsure").toString().toLowerCase());
request.getSession().setAttribute("codeTime", System.currentTimeMillis());

try {
ImageIO.write((BufferedImage) map.get("image"), "JPEG", os);
} catch (IOException e) {
return "";
}
return null;
}

@RequestMapping(value = "/checkcode")
@ResponseBody
public String checkcode(HttpServletRequest request, HttpSession session)
throws Exception {
String checkCode = request.getParameter("checkCode");
Object cko = session.getAttribute("simpleCaptcha"); //验证码对象
if (cko == null) {
request.setAttribute("errorMsg", "验证码已失效,请重新输入!");
return "验证码已失效,请重新输入!";
}

String captcha = cko.toString();
Date now = new Date();
Long codeTime = Long.valueOf(session.getAttribute("codeTime") + "");
if (StringUtils.isEmpty(checkCode) || captcha == null || !(checkCode.equalsIgnoreCase(captcha))) {
request.setAttribute("errorMsg", "验证码错误!");
return "验证码错误!";
} else if ((now.getTime() - codeTime) / 1000 / 60 > 5) {//验证码有效时长为5分钟
request.setAttribute("errorMsg", "验证码已失效,请重新输入!");
return "验证码已失效,请重新输入!";
} else {
session.removeAttribute("simpleCaptcha");
return "1";
}
}
}

9.MainsiteErrorController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MainsiteErrorController implements ErrorController {

private static final String ERROR_PATH = "/error";

@RequestMapping(value=ERROR_PATH)
public String handleError(){
return "403";
}

@Override
public String getErrorPath() {
return "403";
}

@RequestMapping(value="/deny")
public String deny(){
return "deny";
}
}

10.CustomUserDetailsService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import com.chanchifeng.mysql.entity.User;
import com.chanchifeng.mysql.repository.UserRepository;
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;

@Component
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;

@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
User user = userRepository.findByName(userName);
if (user == null) {
throw new UsernameNotFoundException("UserName " + userName + " not found");
}
return new SecurityUser(user);
}
}

11.LoginSuccessHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import com.chanchifeng.mysql.entity.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
protected Log log = LogFactory.getLog(getClass());

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
User userDetails = (User) authentication.getPrincipal();

log.info("登录用户user:" + userDetails.getName() + "login" + request.getContextPath());
log.info("IP:" + getIpAddress(request));
super.onAuthenticationSuccess(request, response, authentication);
}

public String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}

}

12.SecurityUser

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import com.chanchifeng.mysql.entity.Role;
import com.chanchifeng.mysql.entity.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class SecurityUser extends User implements UserDetails {

private static final long serialVersionUID = 1L;

public SecurityUser(User user) {
if (user != null) {
this.setId(user.getId());
this.setName(user.getName());
this.setEmail(user.getEmail());
this.setPassword(user.getPassword());
this.setSex(user.getSex());
this.setCreatedate(user.getCreatedate());
this.setRoles(user.getRoles());
}
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
List<Role> roles = this.getRoles();
if (roles != null) {
for (Role role : roles) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getName());
authorities.add(authority);
}
}
return authorities;
}

@Override
public String getPassword() {
return super.getPassword();
}

@Override
public String getUsername() {
return super.getName();
}

@Override
public boolean isAccountNonExpired() {
return true;
}

@Override
public boolean isAccountNonLocked() {
return true;
}

@Override
public boolean isCredentialsNonExpired() {
return true;
}

@Override
public boolean isEnabled() {
return true;
}

}

13.application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
server:
port: 80
tomcat:
uri-encoding: UTF-8
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username: root
password: 1qaz2wsx
jpa:
database: MYSQL
show-sql: true
## Hibernate ddl auto (validate|create|create-drop|update)
hibernate:
ddl-auto: update
naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
securityconfig:
logoutsuccssurl: /
permitall: /rest/**,/bbs**
deniedpage: /deny
urlroles: /**/new/** = admin;
/**/edit/** = admin,editor;
/**/delete/** = admin

14.web项目的pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>Springboot-Security-UPGRADE</artifactId>
<groupId>com.chanchifeng</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>web</artifactId>
<packaging>jar</packaging>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>com.chanchifeng</groupId>
<artifactId>mysql</artifactId>
<version>${project.version}</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

15.根项目的pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.chanchifeng</groupId>
<artifactId>Springboot-Security-UPGRADE</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>mysql</module>
<module>web</module>
</modules>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>

<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Greenwich.SR1</version>
<relativePath/>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

16.测试JpaConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@EnableJpaRepositories(basePackages = "com.**.repository")
public class JpaConfiguration {

@Bean
PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){
return new PersistenceExceptionTranslationPostProcessor();
}

@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("1qaz2wsx");

return dataSource;
}

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPackagesToScan("com.**.entity");
entityManagerFactoryBean.setJpaProperties(buildHibernateProperties());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter() {{
setDatabase(Database.MYSQL);
}});
return entityManagerFactoryBean;
}

protected Properties buildHibernateProperties()
{
Properties hibernateProperties = new Properties();

hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
hibernateProperties.setProperty("hibernate.show_sql", "true");
hibernateProperties.setProperty("hibernate.use_sql_comments", "false");
hibernateProperties.setProperty("hibernate.format_sql", "true");
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update");
hibernateProperties.setProperty("hibernate.generate_statistics", "false");
hibernateProperties.setProperty("javax.persistence.validation.mode", "none");

//Audit History flags
hibernateProperties.setProperty("org.hibernate.envers.store_data_at_delete", "true");
hibernateProperties.setProperty("org.hibernate.envers.global_with_modified_flag", "true");

return hibernateProperties;
}

@Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager();
}

@Bean
public TransactionTemplate transactionTemplate() {
return new TransactionTemplate(transactionManager());
}
}

17.测试的MysqlTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import com.chanchifeng.mysql.entity.Department;
import com.chanchifeng.mysql.entity.Role;
import com.chanchifeng.mysql.entity.User;
import com.chanchifeng.mysql.repository.DepartmentRepository;
import com.chanchifeng.mysql.repository.RoleRepository;
import com.chanchifeng.mysql.repository.UserRepository;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {JpaConfiguration.class})
public class MysqlTest {
@Autowired
UserRepository userRepository;
@Autowired
DepartmentRepository departmentRepository;
@Autowired
RoleRepository roleRepository;

@Before
public void initData() {
userRepository.deleteAll();
roleRepository.deleteAll();
departmentRepository.deleteAll();

Department department = new Department();
department.setName("开发部");
departmentRepository.save(department);
Assert.notNull(department.getId());

Role role = new Role();
role.setName("admin");
roleRepository.save(role);
Assert.notNull(role.getId());

User user = new User();
user.setName("user");
BCryptPasswordEncoder bpe = new BCryptPasswordEncoder();
user.setPassword(bpe.encode("user"));
user.setCreatedate(new Date());
user.setDepartment(department);
userRepository.save(user);
Assert.notNull(user.getId());
}

@Test
public void insertUserRoles() {
User user = userRepository.findByName("user");
Assert.notNull(user);

List<Role> roles = roleRepository.findAll();
Assert.notNull(roles);
user.setRoles(roles);
userRepository.save(user);
}
}

Github:SpringBoot-Sample/Springboot-Security-UPGRADE

模仿的Github:SpringBoot-Sample/Springboot-Security-SHADOW