一、简介
Web应用的安全管理,主要包括两个方面的内容:身份认证、用户授权,此处使用spring-cloud-security来说明。
二、依赖管理
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity4</artifactId> </dependency> |
三、安全策略配置
Spring Security已经大体实现了,我们这里只是需要一些配置与引用。
|
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 |
package
com.example.demo.config;import
com.example.demo.utils.security.CustomUserService;import
com.example.demo.utils.security.LoginSuccessHandler;import
com.example.demo.utils.security.MyFilterSecurityInterceptor;import
com.example.demo.utils.security.SecuritySettings;import
org.apache.commons.lang3.StringUtils;import
org.springframework.beans.factory.annotation.Autowired;import
org.springframework.context.annotation.Bean;import
org.springframework.context.annotation.Configuration;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.builders.WebSecurity;import
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import
org.springframework.security.core.userdetails.UserDetailsService;import
org.springframework.security.web.access.intercept.FilterSecurityInterceptor;import
org.springframework.security.web.authentication.AuthenticationSuccessHandler;import
org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;/**
* Security安全配置
*
* @Author: 我爱大金子
* @Description: Security安全配置
* @Date: Create in 15:20 2017/7/5
*/@Configuration@EnableWebSecuritypublic
class
WebSecurityConfig
extends
WebSecurityConfigurerAdapter {
@Autowired
private
CustomFilterSecurityInterceptor customFilterSecurityInterceptor;
// 权限管理过滤器
@Autowired
private
SecuritySettings securitySettings;
// 自定义安全配置类
/**注册UserDetailsService的bean*/
@Bean
public
UserDetailsService customUserService(){
return
new
CustomUserService();
}
/**登录认证*/
@Override
protected
void
configure(AuthenticationManagerBuilder auth)
throws
Exception {
auth.userDetailsService(customUserService());
//userDetailsService验证
}
/***设置不拦截规则*/
@Override
public
void
configure(WebSecurity web)
throws
Exception {
web.ignoring().antMatchers(
"/js/**"
,
"/css/**"
,
"/images/**"
,
"/druid/**"
);
}
/**安全策略配置*/
@Override
protected
void
configure(HttpSecurity http)
throws
Exception {
// 设置游客可以访问的URI
if
(StringUtils.isNotBlank(securitySettings.getPermitall())) {
http.authorizeRequests().antMatchers(securitySettings.getPermitall().split(
","
)).permitAll();
}
http.authorizeRequests()
.anyRequest().authenticated()
//任何请求,登录后可以访问
// 配置登录URI、登录失败跳转URI与登录成功后默认跳转URI
.and().formLogin().loginPage(
"/login"
).failureUrl(
"/login?error"
).permitAll().defaultSuccessUrl(
"/"
,
true
).successHandler(loginSuccessHandler())
// 注销行为任意访问
.and().logout().permitAll()
// 设置拒绝访问的提示URI
.and().exceptionHandling().accessDeniedPage(
"/login?illegal"
)
;
http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.
class
);
}
/**登录成功处理器*/
private
AuthenticationSuccessHandler loginSuccessHandler() {
return
new
LoginSuccessHandler();
}} |
说明:
loginPage:设置一个实验自定义的登录URI
loginSuccessHandler:设置自定义的登录处理器
permitAll:是允许访问
accessDeniedPage:配置拒绝访问的提示URI
antMatchers:对URI的配置
了解springcloud架构可以加求求:三五三六二四七二五九
假设我要管理员才可以访问admin文件夹下的内容,如:.antMatchers("/admin/**").hasRole("ROLE_ADMIN"),
也可以设置admin文件夹下的文件可以有多个角色来访问,如:.antMatchers("/admin/**").hasAnyRole("ROLE_ADMIN","ROLE_USER")
也可以通过hasIpAddress来指定某一个ip可以访问该资源,写法如下.antMatchers("/admin/**").hasIpAddress("210.210.210.210")
3.1、自定义安全配置类
为是更方便的使用springSecurity,我们自定义一个权限的配置类,如配置登录的URI、游客访问的URI等配置项
|
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 |
package
com.example.demo.utils.security;import
org.springframework.boot.context.properties.ConfigurationProperties;import
org.springframework.context.annotation.Configuration;/**
* 自定义安全配置类
*
* @Author: 我爱大金子
* @Description: 自定义安全配置类
* @Date: Create in 9:45 2017/7/6
*/@Configuration@ConfigurationProperties
(prefix =
"securityConfig"
)public
class
SecuritySettings {
/**允许访问的URL,多个用逗号分隔*/
private
String permitall;
public
String getPermitall() {
return
permitall;
}
public
void
setPermitall(String permitall) {
this
.permitall = permitall;
}} |
3.2、登录成功处理器
登录成功后,如果需要对用户的行为做一些记录或者执行其它操作,则可以使用登录成功处理器。
|
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 |
package
com.example.demo.utils.security;import
com.example.demo.pojo.SysUser;import
org.springframework.security.core.Authentication;import
org.springframework.security.core.userdetails.User;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;/**
* 登录成功处理器
*
* @Author: 我爱大金子
* @Description: 登录成功处理器
* @Date: Create in 11:35 2017/7/6
*/public
class
LoginSuccessHandler
extends
SavedRequestAwareAuthenticationSuccessHandler {
@Override
public
void
onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws
ServletException, IOException {
User userDetails = (User) authentication.getPrincipal();
System.out.println(
"登录用户:username="
+ userDetails.getUsername() +
", uri="
+ request.getContextPath());
super
.onAuthenticationSuccess(request, response, authentication);
}} |
3.3、springMVC 配置(访问 /login 转向 login.html 页面)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 |
package
com.example.demo.config;import
org.springframework.context.annotation.Configuration;import
org.springframework.web.servlet.config.annotation.ViewControllerRegistry;import
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;/**
* springMVC 配置(注册访问 /login 转向 login.html 页面)
*
* @Author: 我爱大金子
* @Description: springMVC 配置(注册访问 /login 转向 login.html 页面)
* @Date: Create in 16:24 2017/7/5
*/@Configurationpublic
class
WebMvcConfig
extends
WebMvcConfigurerAdapter {
@Override
public
void
addViewControllers(ViewControllerRegistry registry) {
registry.addViewController(
"/login"
).setViewName(
"login"
);
}} |
四、登录认证
在安全策略配置代码中有,主要看自定义的CustomUserService,此类实现了UserDetailsService接口,重写了loadUserByUsername方法
|
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 |
package
com.example.demo.utils.security;import
com.example.demo.dao.SysPermissionDao;import
com.example.demo.dao.SysUserDao;import
com.example.demo.pojo.SysPermission;import
org.springframework.security.core.userdetails.User;import
com.example.demo.pojo.SysUser;import
org.springframework.beans.factory.annotation.Autowired;import
org.springframework.security.core.GrantedAuthority;import
org.springframework.security.core.authority.SimpleGrantedAuthority;import
org.springframework.security.core.userdetails.UserDetails;import
org.springframework.security.core.userdetails.UserDetailsService;import
org.springframework.security.core.userdetails.UsernameNotFoundException;import
java.util.ArrayList;import
java.util.List;/**
* 自定义UserDetailsService,将用户权限交给springsecurity进行管控
*
* @Author: 我爱大金子
* @Description: 将用户权限交给Springsecurity进行管控
* @Date: Create in 16:19 2017/7/5
*/public
class
CustomUserService
implements
UserDetailsService {
@Autowired
private
SysUserDao sysUserDao;
@Autowired
private
SysPermissionDao sysPermissionDao;
@Override
public
UserDetails loadUserByUsername(String username) {
SysUser user = sysUserDao.findByUserName(username);
if
(user !=
null
) {
List<SysPermission> permissions = sysPermissionDao.findByAdminUserId(user.getId());
List<GrantedAuthority> grantedAuthorities =
new
ArrayList <>();
for
(SysPermission permission : permissions) {
if
(permission !=
null
&& permission.getName()!=
null
) {
GrantedAuthority grantedAuthority =
new
SimpleGrantedAuthority(permission.getName());
//1:此处将权限信息添加到 GrantedAuthority 对象中,在后面进行全权限验证时会使用GrantedAuthority 对象。
grantedAuthorities.add(grantedAuthority);
}
}
return
new
User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
else
{
throw
new
UsernameNotFoundException(
"admin: "
+ username +
" do not exist!"
);
}
}} |
五、权限管理
在Security安全配置类中使用了权限管理过滤器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
65
66
67
68
69
70
71
72
73
74
75
76
77 |
package
com.example.demo.utils.security;import
javax.servlet.Filter;import
javax.servlet.FilterChain;import
javax.servlet.FilterConfig;import
javax.servlet.ServletException;import
javax.servlet.ServletRequest;import
javax.servlet.ServletResponse;import
org.springframework.beans.factory.annotation.Autowired;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.stereotype.Service;import
java.io.IOException;/**
* 权限管理过滤器
*
* @Author: 我爱大金子
* @Description: 权限管理过滤器
* @Date: Create in 17:16 2017/7/5
*/@Servicepublic
class
CustomFilterSecurityInterceptor
extends
AbstractSecurityInterceptor
implements
Filter {
@Autowired
private
CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource;
// 权限配置资源管理器
/**权限管理决断器*/
@Autowired
public
void
setMyAccessDecisionManager(CustomAccessDecisionManager customAccessDecisionManager) {
super
.setAccessDecisionManager(customAccessDecisionManager);
}
@Override
public
void
init(FilterConfig filterConfig)
throws
ServletException {
}
@Override
public
void
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws
IOException, ServletException {
FilterInvocation fi =
new
FilterInvocation(request, response, chain);
invoke(fi);
}
public
void
invoke(FilterInvocation fi)
throws
IOException, ServletException {
//fi里面有一个被拦截的url
//里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
//再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够
InterceptorStatusToken token =
super
.beforeInvocation(fi);
try
{
//执行下一个拦截器
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}
finally
{
super
.afterInvocation(token,
null
);
}
}
@Override
public
void
destroy() {
}
@Override
public
Class<?> getSecureObjectClass() {
return
FilterInvocation.
class
;
}
@Override
public
SecurityMetadataSource obtainSecurityMetadataSource() {
return
this
.customFilterInvocationSecurityMetadataSource;
}} |
说明:
customFilterSecurityInterceptor:权限管理过滤器
customAccessDecisionManager:权限管理决断器
customFilterInvocationSecurityMetadataSource:权限配置资源管理器
其中过滤器在系统启动时开始工作,并同时导入权限配置资源管理器和权限管理决断器,对用户访问的资源进行管理。权限管理决断器对用户访问的资源与用户拥有的角色权限进行对比,以此来判断用户是否对某个资源具有访问权限。
5.1、权限管理过滤器
继承与AbstractSecurityInterceptor,实时监控用户的行为,防止用户访问未被授权的资源。
|
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 |
package
com.example.demo.utils.security;import
javax.servlet.Filter;import
javax.servlet.FilterChain;import
javax.servlet.FilterConfig;import
javax.servlet.ServletException;import
javax.servlet.ServletRequest;import
javax.servlet.ServletResponse;import
org.slf4j.Logger;import
org.slf4j.LoggerFactory;import
org.springframework.beans.factory.annotation.Autowired;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.stereotype.Service;import
java.io.IOException;/**
* 权限管理过滤器
*
* @Author: 我爱大金子
* @Description: 权限管理过滤器
* @Date: Create in 17:16 2017/7/5
*/@Servicepublic
class
CustomFilterSecurityInterceptor
extends
AbstractSecurityInterceptor
implements
Filter {
Logger log = LoggerFactory.getLogger(CustomFilterSecurityInterceptor.
class
);
@Autowired
private
CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource;
// 权限配置资源管理器
/**权限管理决断器*/
@Autowired
public
void
setMyAccessDecisionManager(CustomAccessDecisionManager customAccessDecisionManager) {
super
.setAccessDecisionManager(customAccessDecisionManager);
}
@Override
public
void
init(FilterConfig filterConfig)
throws
ServletException {
}
@Override
public
void
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws
IOException, ServletException {
FilterInvocation fi =
new
FilterInvocation(request, response, chain);
log.info(
"【权限管理过滤器】请求URL:"
+ fi.getRequestUrl());
invoke(fi);
}
public
void
invoke(FilterInvocation fi)
throws
IOException, ServletException {
//fi里面有一个被拦截的url
//里面调用CustomFilterInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
//再调用CustomAccessDecisionManager的decide方法来校验用户的权限是否足够
InterceptorStatusToken token =
super
.beforeInvocation(fi);
try
{
//执行下一个拦截器
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}
catch
(Exception e) {
log.error(
"【权限管理过滤器】【异常】"
+ e.getMessage(), e);
}
finally
{
super
.afterInvocation(token,
null
);
}
}
@Override
public
void
destroy() {
}
@Override
public
Class<?> getSecureObjectClass() {
return
FilterInvocation.
class
;
}
@Override
public
SecurityMetadataSource obtainSecurityMetadataSource() {
return
this
.customFilterInvocationSecurityMetadataSource;
}} |
5.2、权限管理决断器
权限管理的关键部分就是决断器,它实现了AccessDecisionManager,重写了decide方法,使用自定义的决断器,在用户访问受保护的资源时,决断器判断用户拥有的角色中是否对改资源具有访问权限,如果没有,则拒绝访问
|
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 |
package
com.example.demo.utils.security;import
org.slf4j.Logger;import
org.slf4j.LoggerFactory;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
org.springframework.stereotype.Service;import
java.util.Collection;import
java.util.Iterator;/**
* 权限管理决断器
*
* @Author: 我爱大金子
* @Description: 权限管理决断器
* @Date: Create in 17:15 2017/7/5
*/@Servicepublic
class
CustomAccessDecisionManager
implements
AccessDecisionManager {
Logger log = LoggerFactory.getLogger(CustomAccessDecisionManager.
class
);
// decide 方法是判定是否拥有权限的决策方法,
//authentication 是释CustomUserService中循环添加到 GrantedAuthority 对象中的权限信息集合.
//object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
//configAttributes 为MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
@Override
public
void
decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws
AccessDeniedException, InsufficientAuthenticationException {
if
(
null
== configAttributes || configAttributes.size() <=
0
) {
return
;
}
ConfigAttribute c;
String needRole;
for
(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
c = iter.next();
needRole = c.getAttribute();
for
(GrantedAuthority ga : authentication.getAuthorities()) {
//authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合
if
(needRole.trim().equals(ga.getAuthority())) {
return
;
}
}
log.info(
"【权限管理决断器】需要role:"
+ needRole);
}
throw
new
AccessDeniedException(
"Access is denied"
);
}
@Override
public
boolean
supports(ConfigAttribute attribute) {
return
true
;
}
@Override
public
boolean
supports(Class<?> clazz) {
return
true
;
}} |
5.3、权限配置资源管理器
权限配置资源管理器实现了FilterInvocationSecurityMetadataSource, 在启动时就去加载了所有的权限列表,权限配置资源管理器为决断器实时提供支持,判断用户访问的资源是否在受保护的范围之内。
|
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 |
package
com.example.demo.utils.security;import
com.example.demo.dao.SysPermissionDao;import
com.example.demo.pojo.SysPermission;import
org.springframework.beans.factory.annotation.Autowired;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.security.web.util.matcher.AntPathRequestMatcher;import
org.springframework.stereotype.Service;import
javax.servlet.http.HttpServletRequest;import
java.util.*;/**
* 权限配置资源管理器
*
* @Author: 我爱大金子
* @Description: 权限配置资源管理器
* @Date: Create in 17:17 2017/7/5
*/@Servicepublic
class
CustomFilterInvocationSecurityMetadataSource
implements
FilterInvocationSecurityMetadataSource {
@Autowired
private
SysPermissionDao sysPermissionDao;
private
HashMap<String, Collection<ConfigAttribute>> map =
null
;
/**
* 加载权限表中所有权限
*/
public
void
loadResourceDefine(){
map =
new
HashMap<>();
Collection<ConfigAttribute> array;
ConfigAttribute cfg;
List<SysPermission> permissions = sysPermissionDao.findAll();
for
(SysPermission permission : permissions) {
array =
new
ArrayList<>();
cfg =
new
SecurityConfig(permission.getName());
//此处只添加了用户的名字,其实还可以添加更多权限的信息,例如请求方法到ConfigAttribute的集合中去。此处添加的信息将会作为MyAccessDecisionManager类的decide的第三个参数。
array.add(cfg);
//用权限的getUrl() 作为map的key,用ConfigAttribute的集合作为 value,
map.put(permission.getUrl(), array);
}
}
//此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
@Override
public
Collection<ConfigAttribute> getAttributes(Object object)
throws
IllegalArgumentException {
if
(map ==
null
) loadResourceDefine();
//object 中包含用户请求的request 信息
HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
AntPathRequestMatcher matcher;
String resUrl;
for
(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {
resUrl = iter.next();
matcher =
new
AntPathRequestMatcher(resUrl);
if
(matcher.matches(request)) {
return
map.get(resUrl);
}
}
return
null
;
}
@Override
public
Collection<ConfigAttribute> getAllConfigAttributes() {
return
null
;
}
@Override
public
boolean
supports(Class<?> clazz) {
return
true
;
}} |
六、根据权限设置连接
对于权限管理,我们可能希望,在一个用户访问的界面中,不是等到用户点击了超链接之后,才来判断用户有没有这个权限,而是按照用户拥有的权限来显示超链接。这样的设计对于用户体验来说,会更友好。
6.1、方法1:使用sec标签(thymeleaf)
在html标签中引入的Spring Security的标签:
|
1 |
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4" |
sec:authentication="name":取当前登录用户的用户名
|
1 |
<
title
sec:authentication
=
"name"
></
title
> |
sec:authorize="hasRole('ROLE_ADMIN'):表示当前用户是否拥有角色ROLE_ADMIN
|
1 |
<
li
sec:authorize
=
"hasRole('ROLE_ADMIN')"
><
a
th:href
=
"@{/admin}"
> admin </
a
></
li
> |
sec:authorize="hasAuthority('admin')":表示当前用户是否拥有权限admin
|
1 |
<
li
sec:authorize
=
"hasAuthority('admin')"
><
a
th:href
=
"@{/admin}"
> admin </
a
></
li
> |
6.2、方法二:代码
在控制层用代码获取是否有权限,然后将标识放入内容中,页面获取处理
七、其它代码
7.1、controller
IndexController.java
|
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 |
package
com.example.demo.controller;import
com.example.demo.domain.Msg;import
org.springframework.stereotype.Controller;import
org.springframework.ui.Model;import
org.springframework.web.bind.annotation.RequestMapping;import
org.springframework.web.bind.annotation.ResponseBody;/**
* 描述
*
* @Author: 我爱大金子
* @Description: 描述
* @Date: Create in 15:25 2017/7/5
*/@Controllerpublic
class
IndexController {
/**系统首页*/
@RequestMapping
(
"/"
)
public
String index(Model model){
Msg msg =
new
Msg(
"测试标题"
,
"测试内容"
,
"欢迎来到HOME页面,您拥有index权限"
);
model.addAttribute(
"msg"
, msg);
return
"home"
;
}
/**系统首页2*/
@RequestMapping
(
"/index2"
)
public
String index2(Model model){
Msg msg =
new
Msg(
"测试标题2"
,
"测试内容2"
,
"欢迎来到HOME页面,您拥有home权限"
);
model.addAttribute(
"msg"
, msg);
return
"home"
;
}
@RequestMapping
(
"/admin"
)
@ResponseBody
public
String hello(){
return
"hello admin"
;
}
@RequestMapping
(
"/yk"
)
@ResponseBody
public
String hello2(){
return
"hello yk"
;
}} |
7.2、dao
SysUserDao.java
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 |
package
com.example.demo.dao;import
com.example.demo.pojo.SysUser;import
org.apache.ibatis.annotations.Mapper;/**
* 系统用户dao
*
* @Author: 我爱大金子
* @Description: 系统用户dao
* @Date: Create in 16:15 2017/7/5
*/@Mapperpublic
interface
SysUserDao {
public
SysUser findByUserName(String username);} |
SysPermissionDao.java
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 |
package
com.example.demo.dao;import
com.example.demo.pojo.SysPermission;import
org.apache.ibatis.annotations.Mapper;import
java.util.List;/**
* 系统权限dao
*
* @Author: 我爱大金子
* @Description: 描述
* @Date: Create in 17:05 2017/7/5
*/@Mapperpublic
interface
SysPermissionDao {
List<SysPermission> findAll();
List<SysPermission> findByAdminUserId(Long userId);} |
7.3、domain
Msg.java
|
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 |
package
com.example.demo.domain;/**
* 描述
*
* @Author: 我爱大金子
* @Description: 描述
* @Date: Create in 16:14 2017/7/5
*/public
class
Msg {
private
String title;
private
String content;
private
String etraInfo;
public
Msg(String title, String content, String etraInfo) {
super
();
this
.title = title;
this
.content = content;
this
.etraInfo = etraInfo;
}
public
String getTitle() {
return
title;
}
public
void
setTitle(String title) {
this
.title = title;
}
public
String getContent() {
return
content;
}
public
void
setContent(String content) {
this
.content = content;
}
public
String getEtraInfo() {
return
etraInfo;
}
public
void
setEtraInfo(String etraInfo) {
this
.etraInfo = etraInfo;
}} |
7.4、pojo
SysUser.java
|
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 |
package
com.example.demo.pojo;import
java.util.List;/**
* 系统用户
*
* @Author: 我爱大金子
* @Description: 系统用户
* @Date: Create in 16:12 2017/7/5
*/public
class
SysUser {
private
Long id;
private
String username;
private
String password;
private
List<SysRole> roles;
public
Long getId() {
return
id;
}
public
void
setId(Long id) {
this
.id = id;
}
public
String getUsername() {
return
username;
}
public
void
setUsername(String username) {
this
.username = username;
}
public
String getPassword() {
return
password;
}
public
void
setPassword(String password) {
this
.password = password;
}
public
List<SysRole> getRoles() {
return
roles;
}
public
void
setRoles(List<SysRole> roles) {
this
.roles = roles;
}} |
SysRole.java
|
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 |
package
com.example.demo.pojo;/**
* 系统角色
*
* @Author: 我爱大金子
* @Description: 系统角色
* @Date: Create in 16:13 2017/7/5
*/public
class
SysRole {
private
Long id;
private
String name;
public
Long getId() {
return
id;
}
public
void
setId(Long id) {
this
.id = id;
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}} |
SysPermission.java
|
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 |
package
com.example.demo.pojo;/**
* 系统权限
*
* @Author: 我爱大金子
* @Description: 系统权限
* @Date: Create in 17:04 2017/7/5
*/public
class
SysPermission {
private
Long id;
//权限名称
private
String name;
//权限描述
private
String descritpion;
//授权链接
private
String url;
//父节点id
private
int
pid;
public
Long getId() {
return
id;
}
public
void
setId(Long id) {
this
.id = id;
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
public
String getDescritpion() {
return
descritpion;
}
public
void
setDescritpion(String descritpion) {
this
.descritpion = descritpion;
}
public
String getUrl() {
return
url;
}
public
void
setUrl(String url) {
this
.url = url;
}
public
int
getPid() {
return
pid;
}
public
void
setPid(
int
pid) {
this
.pid = pid;
}} |
7.5、mapperXX.xml
SysUserDao.xml
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 |
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><
mapper
namespace
=
"com.example.demo.dao.SysUserDao"
>
<
resultMap
id
=
"userMap"
type
=
"SysUser"
>
<
id
property
=
"id"
column
=
"ID"
/>
<
result
property
=
"username"
column
=
"username"
/>
<
result
property
=
"password"
column
=
"PASSWORD"
/>
<
collection
property
=
"roles"
ofType
=
"SysRole"
>
<
result
column
=
"name"
property
=
"name"
/>
</
collection
>
</
resultMap
>
<
select
id
=
"findByUserName"
parameterType
=
"String"
resultMap
=
"userMap"
>
select u.*
,r.name
from sys_user u
LEFT JOIN sys_user_role sru on u.id= sru.sys_user_id
LEFT JOIN sys_role r on sru.sys_role_id=r.id
where username= #{username}
</
select
></
mapper
> |
SysPermissionDao.xml
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 |
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><
mapper
namespace
=
"com.example.demo.dao.SysPermissionDao"
>
<
select
id
=
"findAll"
resultType
=
"SysPermission"
>
SELECT * from sys_permission ;
</
select
>
<
select
id
=
"findByAdminUserId"
parameterType
=
"java.lang.Long"
resultType
=
"SysPermission"
>
SELECT
p.*
FROM sys_user u
LEFT JOIN sys_user_role sru ON u.id= sru.sys_user_id
LEFT JOIN sys_role r ON sru.sys_role_id=r.id
LEFT JOIN sys_role_permission spr ON spr.sys_role_id=r.id
LEFT JOIN Sys_permission p ON p.id =spr.sys_permission_id
WHERE u.id=#{userId}
</
select
></
mapper
> |
7.6、html
login.html
|
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 |
<!DOCTYPE html><
html
xmlns:th
=
"http://www.thymeleaf.org"
><
head
>
<
meta
content
=
"text/html;charset=UTF-8"
/>
<
title
>登录页面</
title
>
<
link
rel
=
"stylesheet"
th:href
=
"@{css/bootstrap.min.css}"
/>
<
style
type
=
"text/css"
>
body {
padding-top: 50px;
}
.starter-template {
padding: 40px 15px;
text-align: center;
}
</
style
></
head
><
body
><
nav
class
=
"navbar navbar-inverse navbar-fixed-top"
>
<
div
class
=
"container"
>
<
div
class
=
"navbar-header"
>
<
a
class
=
"navbar-brand"
href
=
"#"
>Spring Security演示</
a
>
</
div
>
<
div
id
=
"navbar"
class
=
"collapse navbar-collapse"
>
<
ul
class
=
"nav navbar-nav"
>
<
li
><
a
th:href
=
"@{/}"
> 首页 </
a
></
li
>
</
ul
>
</
div
>
<!--/.nav-collapse -->
</
div
></
nav
><
div
class
=
"container"
>
<
div
class
=
"starter-template"
>
<
p
th:if
=
"${param.logout}"
class
=
"bg-warning"
>已成功注销</
p
>
<!-- 1 -->
<
p
th:if
=
"${param.illegal}"
class
=
"bg-warning"
>无权访问,请切换账号登录</
p
>
<!-- 1 -->
<
p
th:if
=
"${param.error}"
class
=
"bg-danger"
>用户名或密码错误</
p
>
<!-- 2 -->
<
h2
>使用账号密码登录</
h2
>
<
form
name
=
"form"
th:action
=
"@{/login}"
action
=
"/login"
method
=
"POST"
>
<!-- 3 -->
<
div
class
=
"form-group"
>
<
label
for
=
"username"
>账号</
label
>
<
input
type
=
"text"
class
=
"form-control"
name
=
"username"
value
=
""
placeholder
=
"账号"
/>
</
div
>
<
div
class
=
"form-group"
>
<
label
for
=
"password"
>密码</
label
>
<
input
type
=
"password"
class
=
"form-control"
name
=
"password"
placeholder
=
"密码"
/>
</
div
>
<
input
type
=
"submit"
id
=
"login"
value
=
"Login"
class
=
"btn btn-primary"
/>
</
form
>
</
div
></
div
></
body
></
html
> |
home.html
|
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 |
<!DOCTYPE html><
html
xmlns:th
=
"http://www.thymeleaf.org"
xmlns:sec
=
"http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
><
head
>
<
meta
content
=
"text/html;charset=UTF-8"
/>
<
title
sec:authentication
=
"name"
></
title
>
<
link
rel
=
"stylesheet"
th:href
=
"@{css/bootstrap.min.css}"
/>
<
style
type
=
"text/css"
>
body {
padding-top: 50px;
}
.starter-template {
padding: 40px 15px;
text-align: center;
}
</
style
></
head
><
body
><
nav
class
=
"navbar navbar-inverse navbar-fixed-top"
>
<
div
class
=
"container"
>
<
div
class
=
"navbar-header"
>
<
a
class
=
"navbar-brand"
href
=
"#"
>Spring Security演示</
a
>
</
div
>
<
div
id
=
"navbar"
class
=
"collapse navbar-collapse"
>
<
ul
class
=
"nav navbar-nav"
>
<
li
><
a
th:href
=
"@{/}"
> 首页 </
a
></
li
>
<
li
sec:authorize
=
"hasAuthority('admin')"
><
a
th:href
=
"@{/admin}"
> admin </
a
></
li
>
</
ul
>
</
div
>
<!--/.nav-collapse -->
</
div
></
nav
><
div
class
=
"container"
>
<
div
class
=
"starter-template"
>
<
h1
th:text
=
"${msg.title}"
></
h1
>
<
p
class
=
"bg-primary"
th:text
=
"${msg.content}"
></
p
>
<
div
>
<
p
class
=
"bg-info"
th:text
=
"${msg.etraInfo}"
></
p
>
</
div
>
<
form
th:action
=
"@{/logout}"
method
=
"post"
>
<
input
type
=
"submit"
class
=
"btn btn-primary"
value
=
"注销"
/>
</
form
>
</
div
></
div
></
body
></
html
> |
源码下载地址
转载于:
https://yq.aliyun.com/articles/557429?spm=a2c4e.11153940.0.0.b9037f7eOUXOJh
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69952307/viewspace-2674986/ ,如需转载,请注明出处,否则将追究法律责任。