├── .gitignore
├── README.md
├── SpringSecurity
├── .gitignore
├── README.md
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── cn
│ │ │ └── geekview
│ │ │ ├── SpringsecurityApplication.java
│ │ │ ├── config
│ │ │ ├── MVCConfig.java
│ │ │ └── SecurityConfig.java
│ │ │ ├── controller
│ │ │ └── HomeController.java
│ │ │ ├── entity
│ │ │ ├── model
│ │ │ │ ├── Msg.java
│ │ │ │ ├── SysRole.java
│ │ │ │ └── SysUser.java
│ │ │ └── repository
│ │ │ │ └── SysUserRepository.java
│ │ │ └── service
│ │ │ └── CustomUserService.java
│ └── resources
│ │ ├── application.properties
│ │ ├── static
│ │ └── css
│ │ │ ├── bootstrap-theme.css
│ │ │ ├── bootstrap-theme.css.map
│ │ │ ├── bootstrap-theme.min.css
│ │ │ ├── bootstrap.css
│ │ │ ├── bootstrap.css.map
│ │ │ ├── bootstrap.min.css
│ │ │ └── signin.css
│ │ └── templates
│ │ ├── index.html
│ │ └── login.html
│ └── test
│ └── java
│ └── cn
│ └── geekview
│ └── SpringsecurityApplicationTests.java
├── init_sql
├── SpringSecurity.sql
├── SpringSecurity2.sql
└── SpringSecurity4.sql
├── springsecurity2
├── .gitignore
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── cn
│ │ │ └── geekview
│ │ │ ├── RequestMappingHandlerConfig.java
│ │ │ ├── Springsecurity2Application.java
│ │ │ ├── config
│ │ │ ├── LoginSuccessHandler.java
│ │ │ ├── MvcConfig.java
│ │ │ ├── MyFilterSecurityInterceptor.java
│ │ │ └── WebSecurityConfig.java
│ │ │ ├── controller
│ │ │ └── BasicController.java
│ │ │ ├── entity
│ │ │ ├── model
│ │ │ │ ├── SysResource.java
│ │ │ │ ├── SysResourceRole.java
│ │ │ │ ├── SysRole.java
│ │ │ │ └── SysUser.java
│ │ │ └── repository
│ │ │ │ ├── SysResourceRepository.java
│ │ │ │ ├── SysRoleRepository.java
│ │ │ │ └── SysUserRepository.java
│ │ │ └── service
│ │ │ ├── CustomAccessDecisionManager.java
│ │ │ ├── CustomInvocationSecurityMetadataSourceService.java
│ │ │ └── CustomUserDetailsService.java
│ └── resources
│ │ ├── application.properties
│ │ └── templates
│ │ ├── admin.html
│ │ ├── deny.html
│ │ ├── home.html
│ │ ├── login.html
│ │ ├── super.html
│ │ ├── user.html
│ │ └── vip.html
│ └── test
│ └── java
│ └── cn
│ └── geekview
│ ├── BasicTest.java
│ └── Springsecurity2ApplicationTests.java
├── springsecurity3
├── .gitignore
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── cn
│ │ │ └── geekview
│ │ │ ├── Springsecurity3Application.java
│ │ │ ├── annotation
│ │ │ ├── EmailValidator.java
│ │ │ └── ValidEmail.java
│ │ │ ├── config
│ │ │ └── WebSecurityConfig.java
│ │ │ ├── controller
│ │ │ ├── IndexController.java
│ │ │ ├── RegistrationController.java
│ │ │ └── UserController.java
│ │ │ ├── entity
│ │ │ ├── model
│ │ │ │ ├── Resource.java
│ │ │ │ ├── Role.java
│ │ │ │ ├── User.java
│ │ │ │ └── VerificationToken.java
│ │ │ └── repository
│ │ │ │ ├── UserRepository.java
│ │ │ │ └── VerificationTokenRepository.java
│ │ │ ├── event
│ │ │ ├── Listener
│ │ │ │ └── RegistrationListener.java
│ │ │ └── OnRegistrationCompleteEvent.java
│ │ │ └── service
│ │ │ ├── IUserService.java
│ │ │ └── impl
│ │ │ └── UserServiceImpl.java
│ └── resources
│ │ ├── application.properties
│ │ └── templates
│ │ ├── emailError.html
│ │ ├── home.html
│ │ ├── login.html
│ │ └── register.html
│ └── test
│ └── java
│ └── cn
│ └── geekview
│ └── Springsecurity3ApplicationTests.java
└── springsecurity4
├── .gitignore
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
├── java
│ └── cn
│ │ └── geekview
│ │ ├── Springsecurity4Application.java
│ │ ├── annotation
│ │ ├── EmailCheck.java
│ │ └── EmailChek.java
│ │ ├── config
│ │ └── security
│ │ │ ├── AccessDecisionManagerImpl.java
│ │ │ ├── CSRFSecurityRequestMatcher.java
│ │ │ ├── FilterInvocationSecurityMetadataSourceImpl.java
│ │ │ └── WebSecurityConfig.java
│ │ ├── controller
│ │ ├── IndexController.java
│ │ └── UserController.java
│ │ ├── domain
│ │ ├── dto
│ │ │ └── RegistraFormDTO.java
│ │ ├── entity
│ │ │ ├── Resource.java
│ │ │ ├── Role.java
│ │ │ ├── User.java
│ │ │ └── ValidateToken.java
│ │ └── repository
│ │ │ ├── ResourceRepository.java
│ │ │ ├── RoleRepository.java
│ │ │ ├── UserRepository.java
│ │ │ └── ValidateTokenRepository.java
│ │ ├── event
│ │ ├── OnRegistrationCompleteEvent.java
│ │ └── listener
│ │ │ └── RegistrationListener.java
│ │ ├── handler
│ │ ├── LoginFailureHandler.java
│ │ └── LoginSuccessHandler.java
│ │ ├── service
│ │ ├── IUserService.java
│ │ └── impl
│ │ │ └── UserServiceImpl.java
│ │ └── util
│ │ └── ValidateCode.java
└── resources
│ ├── application.properties
│ └── templates
│ ├── CSRFTest.html
│ ├── admin.html
│ ├── deny.html
│ ├── home.html
│ ├── login.html
│ ├── regist.html
│ ├── super.html
│ ├── user.html
│ └── vip.html
└── test
└── java
└── cn
└── geekview
└── Springsecurity4ApplicationTests.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | /.idea
3 | target/
4 | /springsecurity2/.mvn
5 | /springsecurity3/.mvn
6 | /springsecurity4/.mvn
7 | !.mvn/wrapper/maven-wrapper.jar
8 |
9 | ### STS ###
10 | .apt_generated
11 | .classpath
12 | .factorypath
13 | .project
14 | .settings
15 | .springBeans
16 |
17 | ### IntelliJ IDEA ###
18 | .idea
19 | *.iws
20 | *.iml
21 | *.ipr
22 |
23 | ### NetBeans ###
24 | nbproject/private/
25 | build/
26 | nbbuild/
27 | dist/
28 | nbdist/
29 | .nb-gradle/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SpringBoot
2 | 此工程主要用于学习SpringBoot相关知识
3 |
4 | 目前新增了四个模块:
5 |
6 | 1、SpringSecurity: 用户和权限用数据库存储,而资源(url)和权限的对应采用硬编码配置。
7 | 2、SpringSecurity2: 用户、角色、权限和资源均采用数据库存储
8 | 3、SpringSecurity3:用户注册、邮箱验证
9 | 4、SpringSecurity4:注册登录合并
10 |
11 | 注:每个模块里面的README文件有对应模块的简要说明,时间关系,可能写的比较简陋一些,多担待,有问题请提issue
12 |
13 |
14 | 思考与总结:
15 |
16 | 1、将资源、角色、用户全部分开保存在数据库,再建立中间表进行管理处理,这样操作比较麻烦:
17 | **在使用前,需要先配置角色可以访问那些资源的中间表**,可以自己写代码处理,
18 | 比较简单一点的方式就是:
19 | **只对用户进行角色的区分,具体哪一个角色具备哪些权限,由注解来决定:@PreAuthorize("hasRole('ROLE')"**)
20 | 这样在Controller的路径下添加注解,就只需要管理用户和角色了,
21 | 这样的缺陷是:
22 | 如果资源对应的角色需要修改的时候需要重新修改代码;
23 | 如果想直接根据用户的角色显示对应的内容,当然也可以处理,又要单独实现一圈,
24 |
25 |
--------------------------------------------------------------------------------
/SpringSecurity/.gitignore:
--------------------------------------------------------------------------------
1 | /.mvn
2 | /mvnw
3 | /mvnw.cmd
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 |
13 | ### IntelliJ IDEA ###
14 | .idea
15 | *.iws
16 | *.iml
17 | *.ipr
18 |
19 | ### NetBeans ###
20 | nbproject/private/
21 | build/
22 | nbbuild/
23 | dist/
24 | nbdist/
25 | .nb-gradle/
26 |
27 | ### Java ###
28 | target/
29 |
--------------------------------------------------------------------------------
/SpringSecurity/README.md:
--------------------------------------------------------------------------------
1 | # SpringSecurity
2 | SpringBoot和SpringSecurity整合方式2:
3 |
4 | 用户和权限用数据库存储,而资源(url)和权限的对应采用硬编码配置。
5 |
--------------------------------------------------------------------------------
/SpringSecurity/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | cn.geekview
7 | springsecurity
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | springsecurity
12 | Demo project for Spring Boot With Spring Security
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.5.9.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-data-jpa
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-data-redis
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-mail
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-security
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-starter-thymeleaf
47 |
48 |
49 | org.thymeleaf.extras
50 | thymeleaf-extras-springsecurity4
51 |
52 |
53 | org.springframework.boot
54 | spring-boot-starter-web
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-devtools
59 | runtime
60 |
61 |
62 | mysql
63 | mysql-connector-java
64 | runtime
65 |
66 |
67 | org.springframework.boot
68 | spring-boot-starter-test
69 | test
70 |
71 |
72 | org.springframework.security
73 | spring-security-test
74 | test
75 |
76 |
77 | org.springframework.social
78 | spring-social-core
79 |
80 |
81 | org.springframework.social
82 | spring-social-config
83 |
84 |
85 | org.springframework.social
86 | spring-social-web
87 |
88 |
89 | org.springframework.social
90 | spring-social-security
91 |
92 |
93 |
94 |
95 |
96 |
97 | org.springframework.boot
98 | spring-boot-maven-plugin
99 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/java/cn/geekview/SpringsecurityApplication.java:
--------------------------------------------------------------------------------
1 | package cn.geekview;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SpringsecurityApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(SpringsecurityApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/java/cn/geekview/config/MVCConfig.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
6 |
7 | /**
8 | * MVC配置类
9 | * 这个可以直接进行跳转,不需要经过Controller
10 | */
11 | @Configuration
12 | public class MVCConfig extends WebMvcConfigurerAdapter{
13 |
14 | @Override
15 | public void addViewControllers(ViewControllerRegistry registry) {
16 | registry.addViewController("/login").setViewName("login");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/java/cn/geekview/config/SecurityConfig.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config;
2 |
3 | import cn.geekview.service.CustomUserService;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
8 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
9 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
10 | import org.springframework.security.core.userdetails.UserDetailsService;
11 |
12 | /**
13 | * Spring Security 配置类
14 | */
15 | @Configuration
16 | @EnableWebSecurity
17 | public class SecurityConfig extends WebSecurityConfigurerAdapter {
18 |
19 | @Bean
20 | UserDetailsService customUserService(){
21 | return new CustomUserService();
22 | }
23 |
24 | @Override
25 | protected void configure(AuthenticationManagerBuilder auth) throws Exception {
26 | auth.userDetailsService(customUserService());
27 | }
28 |
29 | /**
30 | * 定义哪些URL需要被保护
31 | * @param http
32 | * @throws Exception
33 | */
34 | @Override
35 | protected void configure(HttpSecurity http) throws Exception {
36 | http.authorizeRequests()
37 | .anyRequest().authenticated()
38 | .and().formLogin().loginPage("/login").failureUrl("/login?error").permitAll().and()
39 | .logout().permitAll();
40 | }
41 |
42 |
43 |
44 | /**
45 | *
46 | * @param auth
47 | * @throws Exception
48 | */
49 | // @Override
50 | // protected void configure(AuthenticationManagerBuilder auth) throws Exception {
51 | // //将单个用户设置在内存中
52 | //// super.configure(auth);//根据默认实现获取一个AuthenticationManager---》调用WebSecurityConfigurerAdapter的authenticationManager()方法
53 | // // 这里加入内存有哪些用户,页面登录就可以输入哪些用户登录
54 | // auth.inMemoryAuthentication().withUser("admin").password("password").roles("USER");
55 | //
56 | // }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/java/cn/geekview/controller/HomeController.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.controller;
2 |
3 | import cn.geekview.entity.model.Msg;
4 | import org.springframework.stereotype.Controller;
5 | import org.springframework.ui.Model;
6 | import org.springframework.web.bind.annotation.RequestMapping;
7 |
8 | @Controller
9 | public class HomeController {
10 | @RequestMapping("/")
11 | public String index(Model model) {
12 | Msg msg = new Msg("测试标题", "测试内容", "额外信息,只对管理员显示");
13 | model.addAttribute("msg", msg);
14 | return "index";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/java/cn/geekview/entity/model/Msg.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | public class Msg {
4 | private String title;
5 | private String content;
6 | private String extraInfo;
7 |
8 | public Msg() {
9 | }
10 |
11 | public String getTitle() {
12 | return title;
13 | }
14 |
15 | public void setTitle(String title) {
16 | this.title = title;
17 | }
18 |
19 | public String getContent() {
20 | return content;
21 | }
22 |
23 | public void setContent(String content) {
24 | this.content = content;
25 | }
26 |
27 | public String getExtraInfo() {
28 | return extraInfo;
29 | }
30 |
31 | public void setExtraInfo(String extraInfo) {
32 | this.extraInfo = extraInfo;
33 | }
34 |
35 | public Msg(String title, String content, String extraInfo) {
36 | this.title = title;
37 | this.content = content;
38 | this.extraInfo = extraInfo;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/java/cn/geekview/entity/model/SysRole.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | import javax.persistence.Entity;
4 | import javax.persistence.GeneratedValue;
5 | import javax.persistence.Id;
6 |
7 | @Entity
8 | public class SysRole {
9 |
10 | @Id
11 | @GeneratedValue
12 | private Long id;
13 |
14 | private String name;
15 |
16 | public Long getId() {
17 | return id;
18 | }
19 |
20 | public void setId(Long id) {
21 | this.id = id;
22 | }
23 |
24 | public String getName() {
25 | return name;
26 | }
27 |
28 | public void setName(String name) {
29 | this.name = name;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/java/cn/geekview/entity/model/SysUser.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | import org.springframework.security.core.GrantedAuthority;
4 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
5 | import org.springframework.security.core.userdetails.UserDetails;
6 |
7 | import javax.persistence.*;
8 | import java.util.ArrayList;
9 | import java.util.Collection;
10 | import java.util.List;
11 |
12 | /**
13 | *
14 | * 实现UserDetails接口,这样我们的用户实体即为Spring Security所使用的用户
15 | *
16 | */
17 |
18 | @Entity
19 | public class SysUser implements UserDetails{
20 | @Id
21 | @GeneratedValue
22 | private Long id;
23 | private String username;//不能写成userName
24 | private String password;//不能写成passWord
25 |
26 | @ManyToMany(cascade = CascadeType.REFRESH,fetch = FetchType.EAGER)
27 | private List roles;
28 |
29 | public Long getId() {
30 | return id;
31 | }
32 |
33 | public void setId(Long id) {
34 | this.id = id;
35 | }
36 |
37 | @Override
38 | public String getUsername() {
39 | return username;
40 | }
41 |
42 | public void setUsername(String username) {
43 | this.username = username;
44 | }
45 |
46 | @Override
47 | public String getPassword() {
48 | return password;
49 | }
50 |
51 | public void setPassword(String password) {
52 | this.password = password;
53 | }
54 |
55 | public List getRoles() {
56 | return roles;
57 | }
58 |
59 | public void setRoles(List roles) {
60 | this.roles = roles;
61 | }
62 |
63 | @Override
64 | public boolean isAccountNonExpired() {
65 | return true;
66 | }
67 |
68 | @Override
69 | public boolean isAccountNonLocked() {
70 | return true;
71 | }
72 |
73 | @Override
74 | public boolean isCredentialsNonExpired() {
75 | return true;
76 | }
77 |
78 | @Override
79 | public boolean isEnabled() {
80 | return true;
81 | }
82 |
83 | /*
84 | 正常情况下,角色和权限是两回事,所以我们还需要重写getAuthorities方法,将用户的角色和权限关联起来
85 | */
86 | @Override
87 | public Collection extends GrantedAuthority> getAuthorities() {
88 | List authorities = new ArrayList<>();
89 | List roles = this.roles;
90 | for (SysRole role : roles) {
91 | authorities.add(new SimpleGrantedAuthority(role.getName()));
92 | }
93 | return authorities;
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/java/cn/geekview/entity/repository/SysUserRepository.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.repository;
2 |
3 | import cn.geekview.entity.model.SysUser;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface SysUserRepository extends JpaRepository {
7 | SysUser findByUsername(String username);
8 | }
9 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/java/cn/geekview/service/CustomUserService.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.service;
2 |
3 | import cn.geekview.entity.model.SysUser;
4 | import cn.geekview.entity.repository.SysUserRepository;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.security.core.userdetails.UserDetails;
7 | import org.springframework.security.core.userdetails.UserDetailsService;
8 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
9 | import org.springframework.stereotype.Service;
10 |
11 | @Service
12 | public class CustomUserService implements UserDetailsService {
13 |
14 | @Autowired
15 | private SysUserRepository userRepository;
16 |
17 | @Override
18 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
19 | SysUser user = userRepository.findByUsername(username);
20 | if (user==null){
21 | throw new UsernameNotFoundException("用户名不存在");
22 | }
23 | System.out.println("username:"+username);
24 | System.out.println("username:"+user.getUsername()+";password:"+user.getPassword());
25 | return user;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScnuWang/SpringBoot/dab0a4c95389a69f3dbaadb09d28741e4d706c66/SpringSecurity/src/main/resources/application.properties
--------------------------------------------------------------------------------
/SpringSecurity/src/main/resources/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
18 |
19 |
20 |
33 |
34 |
35 |
36 |
37 |
40 |
43 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/SpringSecurity/src/main/resources/templates/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 登录
6 |
7 |
8 |
17 |
18 |
19 |
32 |
33 |
34 |
已注销
35 |
有错误,请重试
36 |
使用账号密码登录
37 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/SpringSecurity/src/test/java/cn/geekview/SpringsecurityApplicationTests.java:
--------------------------------------------------------------------------------
1 | package cn.geekview;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class SpringsecurityApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/init_sql/SpringSecurity.sql:
--------------------------------------------------------------------------------
1 | insert into `sys_role`(`id`,`name`) values (1,'ROLE_USER'),(2,'ROLE_VIP'),(3,'ROLE_ADMIN'),(4,'ROLE_SUPER_ADMIN');
2 | insert into `sys_user`(`id`,`password`,`username`) values (1,'user','user'),(2,'vip','vip'),(3,'admin','admin'),(4,'sadmin','sadmin');
3 | insert into `sys_user_roles`(`sys_user_id`,`roles_id`) values (1,1),(2,2),(3,3),(4,4);
--------------------------------------------------------------------------------
/init_sql/SpringSecurity2.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO `spring_boot`.`sys_user` (`id`, `password`, `username`) VALUES ('1', '$2a$04$5EzhLxOthTOMc5pN/Ozg1.wzrbijftcgEqXPouJt7igKIoxAmVWtO', 'liuyan');
2 | INSERT INTO `spring_boot`.`sys_user` (`id`, `password`, `username`) VALUES ('2', '$2a$04$2/GN1BIPc6agihyHMQce4OSr34CgPCTRgiTQYEr51Wc1zm7u5eOTm', 'dongdong');
3 | INSERT INTO `spring_boot`.`sys_user` (`id`, `password`, `username`) VALUES ('3', '$2a$04$3Cksa3X0bYdYDkDm231w/uZ8BWJiV57OKTG9PZo8iFHTxNZ1jT77a', 'admin');
4 | INSERT INTO `spring_boot`.`sys_user` (`id`, `password`, `username`) VALUES ('4', '$2a$04$3Cksa3X0bYdYDkDm231w/uZ8BWJiV57OKTG9PZo8iFHTxNZ1jT77a', 'jason');
5 |
6 | INSERT INTO `spring_boot`.`sys_role` (`id`, `role_name`) VALUES ('1', 'USER');
7 | INSERT INTO `spring_boot`.`sys_role` (`id`, `role_name`) VALUES ('2', 'ADMIN');
8 | INSERT INTO `spring_boot`.`sys_role` (`id`, `role_name`) VALUES ('3', 'VIP');
9 | INSERT INTO `spring_boot`.`sys_role` (`id`, `role_name`) VALUES ('4', 'SUPER');
10 |
11 |
12 | INSERT INTO `spring_boot`.`sys_resource` (`id`, `resource_name`) VALUES ('1', '/vip');
13 | INSERT INTO `spring_boot`.`sys_resource` (`id`, `resource_name`) VALUES ('2', '/user');
14 | INSERT INTO `spring_boot`.`sys_resource` (`id`, `resource_name`) VALUES ('3', '/admin');
15 | INSERT INTO `spring_boot`.`sys_resource` (`id`, `resource_name`) VALUES ('4', '/super');
16 |
17 |
18 | INSERT INTO `spring_boot`.`sys_user_roles` (`sys_user_id`, `roles_id`) VALUES ('3', '2');
19 | INSERT INTO `spring_boot`.`sys_user_roles` (`sys_user_id`, `roles_id`) VALUES ('1', '3');
20 | INSERT INTO `spring_boot`.`sys_user_roles` (`sys_user_id`, `roles_id`) VALUES ('2', '1');
21 | INSERT INTO `spring_boot`.`sys_user_roles` (`sys_user_id`, `roles_id`) VALUES ('4', '4');
22 |
23 |
24 | INSERT INTO `spring_boot`.`sys_resource_role` (`id`, `resource_id`, `role_id`) VALUES ('1', '2', '1');
25 | INSERT INTO `spring_boot`.`sys_resource_role` (`id`, `resource_id`, `role_id`) VALUES ('2', '1', '3');
26 | INSERT INTO `spring_boot`.`sys_resource_role` (`id`, `resource_id`, `role_id`) VALUES ('3', '3', '2');
27 | INSERT INTO `spring_boot`.`sys_resource_role` (`id`, `resource_id`, `role_id`) VALUES ('4', '1', '2');
28 | INSERT INTO `spring_boot`.`sys_resource_role` (`id`, `resource_id`, `role_id`) VALUES ('5', '4', '4');
29 | INSERT INTO `spring_boot`.`sys_resource_role` (`id`, `resource_id`, `role_id`) VALUES ('6', '2', '4');
30 | INSERT INTO `spring_boot`.`sys_resource_role` (`id`, `resource_id`, `role_id`) VALUES ('7', '3', '4');
31 | INSERT INTO `spring_boot`.`sys_resource_role` (`id`, `resource_id`, `role_id`) VALUES ('8', '1', '4');
32 | INSERT INTO `spring_boot`.`sys_resource_role` (`id`, `resource_id`, `role_id`) VALUES ('9', '2', '2');
33 | INSERT INTO `spring_boot`.`sys_resource_role` (`id`, `resource_id`, `role_id`) VALUES ('10', '2', '3');
34 |
35 | CREATE TABLE persistent_logins (
36 | username VARCHAR (64) NOT NULL,
37 | series VARCHAR (64) PRIMARY KEY,
38 | token VARCHAR (64) NOT NULL,
39 | last_used TIMESTAMP NOT NULL
40 | )
--------------------------------------------------------------------------------
/init_sql/SpringSecurity4.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO `spring_boot`.`t_role` (`id`, `role_name`) VALUES ('1', 'USER');
2 | INSERT INTO `spring_boot`.`t_role` (`id`, `role_name`) VALUES ('2', 'ADMIN');
3 | INSERT INTO `spring_boot`.`t_role` (`id`, `role_name`) VALUES ('3', 'VIP');
4 | INSERT INTO `spring_boot`.`t_role` (`id`, `role_name`) VALUES ('4', 'SUPER');
5 |
6 |
7 | INSERT INTO `spring_boot`.`t_resource` (`id`, `resource`) VALUES ('1', '/vip');
8 | INSERT INTO `spring_boot`.`t_resource` (`id`, `resource`) VALUES ('2', '/user');
9 | INSERT INTO `spring_boot`.`t_resource` (`id`, `resource`) VALUES ('3', '/admin');
10 | INSERT INTO `spring_boot`.`t_resource` (`id`, `resource`) VALUES ('4', '/super');
11 |
12 | INSERT INTO `spring_boot`.`t_role_resources` (`roles_id` , `resources_id` ) VALUES ('1', '2');
13 | INSERT INTO `spring_boot`.`t_role_resources` (`roles_id` , `resources_id` ) VALUES ('1', '3');
14 | INSERT INTO `spring_boot`.`t_role_resources` (`roles_id` , `resources_id` ) VALUES ('3', '2');
15 | INSERT INTO `spring_boot`.`t_role_resources` (`roles_id` , `resources_id` ) VALUES ('2', '1');
16 | INSERT INTO `spring_boot`.`t_role_resources` (`roles_id` , `resources_id` ) VALUES ('4', '2');
17 | INSERT INTO `spring_boot`.`t_role_resources` (`roles_id` , `resources_id` ) VALUES ('4', '3');
18 | INSERT INTO `spring_boot`.`t_role_resources` (`roles_id` , `resources_id` ) VALUES ('4', '1');
19 | INSERT INTO `spring_boot`.`t_role_resources` (`roles_id` , `resources_id` ) VALUES ('2', '2');
20 | INSERT INTO `spring_boot`.`t_role_resources` (`roles_id` , `resources_id` ) VALUES ('3', '2');
21 |
22 | CREATE TABLE persistent_logins (
23 | username VARCHAR (64) NOT NULL,
24 | series VARCHAR (64) PRIMARY KEY,
25 | token VARCHAR (64) NOT NULL,
26 | last_used TIMESTAMP NOT NULL
27 | );
28 |
29 |
30 | INSERT INTO `spring_boot`.`t_user_roles` (`users_id`, `roles_id`) VALUES ('3', '2');
31 | INSERT INTO `spring_boot`.`t_user_roles` (`users_id`, `roles_id`) VALUES ('1', '3');
32 | INSERT INTO `spring_boot`.`t_user_roles` (`users_id`, `roles_id`) VALUES ('2', '1');
33 | INSERT INTO `spring_boot`.`t_user_roles` (`users_id`, `roles_id`) VALUES ('4', '4');
--------------------------------------------------------------------------------
/springsecurity2/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | ### STS ###
5 | .apt_generated
6 | .classpath
7 | .factorypath
8 | .project
9 | .settings
10 | .springBeans
11 |
12 | ### IntelliJ IDEA ###
13 | .idea
14 | *.iws
15 | *.iml
16 | *.ipr
17 |
18 | ### NetBeans ###
19 | nbproject/private/
20 | build/
21 | nbbuild/
22 | dist/
23 | nbdist/
24 | .nb-gradle/
--------------------------------------------------------------------------------
/springsecurity2/README.md:
--------------------------------------------------------------------------------
1 | # SpringSecurity
2 | SpringBoot和SpringSecurity整合方式2:
3 |
4 | 细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,
5 | 并且自定义过滤器,代替原有的FilterSecurityInterceptor过滤器
6 | 并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,
7 | 并在配置文件中进行相应配置。
8 |
9 | 测试账号:
10 |
11 | admin/123456
12 | liuyan/123456
13 | dongdong/123456
14 | jason/123456
15 |
16 | 操作步骤:
17 |
18 | 1、使用IDEA(也可以用其他类似工具如:Eclipse)直接下载安装工程
19 | 2、修改数据库相关信息
20 | 3、启动**SpringSecurity2**模块
21 | 4、初始化init_sql目录里面的SpringSecurity2.sql初始化语句
22 | 5、访问localhost,然后使用上面的测试账号登录
23 |
24 |
25 | 需求1:
26 |
27 | 登录成功后默认跳转到对应展示的页面
28 | admin---》/admin
29 | vip---》/vip
30 | user---》/user
31 | super---》/super
32 | 访问其他权限的页面,会提示权限不足
33 | 测试通过
34 |
35 | 需求2:
36 |
37 | super登陆后可以访问/super、/admin、/vip、/user
38 | admin登录后可以访问/admin、/vip、/user
39 | vip登录后可以访问/vip、/user
40 | user登录后可以访问/user
41 | 测试通过
42 |
43 | 需求3:
44 |
45 | Cookie快速登录
46 |
47 | 测试通过
48 |
49 | 目前缺陷1:~~资源和角色一一对应~~
50 |
51 | 目前缺陷2:~~Remenber Me持久化到数据库没有实现~~
52 |
53 | 目前缺陷3:~~前端获取不到权限验证失败的信息(异常信息)~~
54 |
55 |
56 |
--------------------------------------------------------------------------------
/springsecurity2/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Migwn, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | echo $MAVEN_PROJECTBASEDIR
205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
206 |
207 | # For Cygwin, switch paths to Windows format before running java
208 | if $cygwin; then
209 | [ -n "$M2_HOME" ] &&
210 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
211 | [ -n "$JAVA_HOME" ] &&
212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
213 | [ -n "$CLASSPATH" ] &&
214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
215 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
217 | fi
218 |
219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
220 |
221 | exec "$JAVACMD" \
222 | $MAVEN_OPTS \
223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
226 |
--------------------------------------------------------------------------------
/springsecurity2/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/springsecurity2/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | cn.geekview
7 | springsecurity2
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | springsecurity2
12 | Demo project for Spring Boot With Spring Security
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.5.9.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-data-jpa
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-security
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-thymeleaf
39 |
40 |
41 | mysql
42 | mysql-connector-java
43 | runtime
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-test
48 | test
49 |
50 |
51 | org.springframework.security
52 | spring-security-test
53 | test
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-autoconfigure
58 |
59 |
60 |
61 |
62 |
63 |
64 | org.springframework.boot
65 | spring-boot-maven-plugin
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/RequestMappingHandlerConfig.java:
--------------------------------------------------------------------------------
1 | package cn.geekview;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
6 |
7 | @Configuration
8 | public class RequestMappingHandlerConfig {
9 | @Bean
10 | public RequestMappingHandlerMapping requestMappingHandlerMapping() {
11 | RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping();
12 | return mapping;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/Springsecurity2Application.java:
--------------------------------------------------------------------------------
1 | package cn.geekview;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.web.method.HandlerMethod;
8 | import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
9 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
10 |
11 | import javax.annotation.PostConstruct;
12 | import java.util.HashMap;
13 | import java.util.Map;
14 | import java.util.Set;
15 |
16 | @SpringBootApplication
17 | @EnableAutoConfiguration //注意如果:MyFilterSecurityInterceptor.class
18 | //@EnableAutoConfiguration(exclude = MyFilterSecurityInterceptor.class) // 没有才装配,有就以个人装配为准
19 | public class Springsecurity2Application {
20 |
21 | @Autowired
22 | private RequestMappingHandlerConfig requestMappingHandlerConfig;
23 |
24 | public static void main(String[] args) {
25 | SpringApplication.run(Springsecurity2Application.class, args);
26 | }
27 |
28 | // 获取资源路径 : 只能获取Controller上面的路径,通过继承WebMvcConfigurerAdapter的类添加的路径映射,不能获取
29 | @PostConstruct
30 | public void detectresource(){
31 | final RequestMappingHandlerMapping requestMappingHandlerMapping = requestMappingHandlerConfig.requestMappingHandlerMapping ();
32 | Map map = requestMappingHandlerMapping.getHandlerMethods();
33 | Set mappings = map.keySet();
34 | Map reversedMap = new HashMap();
35 | for(RequestMappingInfo info : mappings) {
36 | HandlerMethod method = map.get(info);
37 | String methodstr = method.toString();
38 | methodstr = methodstr.split("\\(")[0];
39 |
40 | String urlparm = info.getPatternsCondition().toString();
41 | String url = urlparm.substring(1, urlparm.length()-1);
42 | System.out.println("方法路径:"+methodstr);
43 | System.out.println("请求相对路径:"+url);
44 | // 数据库操作
45 | // List list = sresourceService.findByResourceString(url);
46 | // if(list==null || list.size()<=0){
47 | // int num = (int)(Math.random()*100+1);
48 | // String rand = String.valueOf(num);
49 | // String resourceId = "res"+System.currentTimeMillis()+rand;
50 | // SysResource sysresource = new SysResource();
51 | // sysresource.setResourceString(url);
52 | // sysresource.setRemark("0");
53 | // sysresource.setResourceId(resourceId);
54 | // sysresource.setMethodPath(methodstr);
55 | // sresourceService.save(sysresource);
56 | // System.out.println ("===>"+url);
57 | // }
58 |
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/config/LoginSuccessHandler.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config;
2 |
3 | import java.io.IOException;
4 |
5 | import javax.servlet.ServletException;
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 |
9 | import cn.geekview.entity.model.SysUser;
10 | import cn.geekview.entity.repository.SysResourceRepository;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.security.core.Authentication;
13 | import org.springframework.security.core.GrantedAuthority;
14 | import org.springframework.security.core.context.SecurityContextHolder;
15 | import org.springframework.security.web.DefaultRedirectStrategy;
16 | import org.springframework.security.web.RedirectStrategy;
17 | import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
18 |
19 | /**
20 | * 登录成功处理器
21 | * 需求:
22 | * 登录成功后,默认跳转到对应角色下的页面
23 | */
24 | public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
25 |
26 | @Autowired
27 | private SysResourceRepository resourceRepository;
28 |
29 | private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
30 |
31 | @Override
32 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException,
33 | ServletException {
34 | System.out.println(authentication);
35 |
36 | System.out.println(authentication.getPrincipal());//用户对象
37 | //获得授权后可得到用户信息
38 | SysUser user = (SysUser)authentication.getPrincipal();
39 |
40 | //输出登录提示信息
41 | System.out.println("用户名: " + user.getUsername());
42 |
43 | System.out.println("用户密码: " + authentication.getCredentials());
44 |
45 | System.out.println("角色列表:"+authentication.getAuthorities());
46 |
47 | System.out.println("IP信息 :"+authentication.getDetails());
48 |
49 | System.out.println("是否被授权 :"+authentication.isAuthenticated());
50 |
51 | //登录成功后跳转到默认对应的页面
52 | String targetUrl = "/home";
53 | for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
54 | String roleName = grantedAuthority.getAuthority();
55 | switch (roleName){
56 | case "SUPER": targetUrl = "/super";break;
57 | case "ADMIN": targetUrl = "/admin";break;
58 | case "VIP": targetUrl = "/vip";break;
59 | case "USER": targetUrl = "/user";break;
60 | }
61 | }
62 | redirectStrategy.sendRedirect(request,response,targetUrl);
63 |
64 | // System.out.println("----->"+resourceRepository.findByRoleName(userDetails.getRoles().get(0).getRoleName()).get(0).getResourceName());
65 | //登录成功后跳转到默认对应的页面
66 | // response.sendRedirect(resourceRepository.findByRoleName(userDetails.getRoles().get(0).getRoleName()).get(0).getResourceName());
67 | // super.onAuthenticationSuccess(request, response, authentication);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/config/MvcConfig.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
6 |
7 | //@Configuration
8 | //public class MvcConfig extends WebMvcConfigurerAdapter {
9 | //
10 | // @Override
11 | // public void addViewControllers(ViewControllerRegistry registry) {
12 | // registry.addViewController("/home").setViewName("home");
13 | // registry.addViewController("/").setViewName("home");
14 | // registry.addViewController("/admin").setViewName("admin");
15 | // registry.addViewController("/user").setViewName("user");
16 | // registry.addViewController("/vip").setViewName("vip");
17 | // registry.addViewController("/login").setViewName("login");
18 | // registry.addViewController("/super").setViewName("super");
19 | // registry.addViewController("/deny").setViewName("deny");
20 | // }
21 | //
22 | //}
23 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/config/MyFilterSecurityInterceptor.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config;
2 |
3 | import cn.geekview.service.CustomAccessDecisionManager;
4 | import cn.geekview.service.CustomInvocationSecurityMetadataSourceService;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.security.access.SecurityMetadataSource;
7 | import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
8 | import org.springframework.security.access.intercept.InterceptorStatusToken;
9 | import org.springframework.security.authentication.AuthenticationManager;
10 | import org.springframework.security.web.FilterInvocation;
11 | import org.springframework.stereotype.Component;
12 |
13 | import javax.annotation.PostConstruct;
14 | import javax.servlet.*;
15 | import java.io.IOException;
16 |
17 | /**
18 | * 该过滤器的主要作用就是通过spring著名的IoC生成securityMetadataSource。
19 | * securityMetadataSource相当于本包中自定义的MyInvocationSecurityMetadataSourceService。
20 | * 该MyInvocationSecurityMetadataSourceService的作用提从数据库提取权限和资源,装配到HashMap中,
21 | * 供Spring Security使用,用于权限校验。
22 | * @author sparta 11/3/29
23 | *
24 | */
25 | //@Component
26 | //public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter{
27 | //
28 | // @Autowired
29 | // private CustomInvocationSecurityMetadataSourceService mySecurityMetadataSource;
30 | //
31 | // @Autowired
32 | // private CustomAccessDecisionManager myAccessDecisionManager;
33 | //
34 | // /**
35 | // * 在WebSecurityConfig类中configureGlobal(AuthenticationManagerBuilder auth)已经创建
36 | // */
37 | // @Autowired
38 | // private AuthenticationManager authenticationManager;
39 | // /**
40 | // * 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,
41 | // * 被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。
42 | // */
43 | // @PostConstruct
44 | // public void init(){
45 | // super.setAuthenticationManager(authenticationManager);
46 | // super.setAccessDecisionManager(myAccessDecisionManager);
47 | // }
48 | //
49 | // public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{
50 | // FilterInvocation filterInvocation = new FilterInvocation( request, response, chain );
51 | // invoke(filterInvocation);
52 | // }
53 | //
54 | //
55 | // public Class extends Object> getSecureObjectClass(){
56 | // return FilterInvocation.class;
57 | // }
58 | //
59 | //
60 | // public void invoke( FilterInvocation filterInvocation ) throws IOException, ServletException{
61 | // System.out.println("MyFilterSecurityInterceptor --> invoke..........................");
62 | // InterceptorStatusToken token = super.beforeInvocation(filterInvocation);
63 | // try{
64 | // filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
65 | // }finally{
66 | // super.afterInvocation(token, null);
67 | // }
68 | // }
69 | //
70 | //
71 | // @Override
72 | // public SecurityMetadataSource obtainSecurityMetadataSource(){
73 | // System.out.println("MyFilterSecurityInterceptor 中的 obtainSecurityMetadataSource()方法");
74 | // return this.mySecurityMetadataSource;
75 | // }
76 | //
77 | // public void destroy(){
78 | // System.out.println("filter===========================end");
79 | // }
80 | // public void init( FilterConfig filterconfig ) throws ServletException{
81 | // System.out.println("filter===========================");
82 | // }
83 | //}
84 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/config/WebSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config;
2 |
3 | import cn.geekview.service.CustomAccessDecisionManager;
4 | import cn.geekview.service.CustomInvocationSecurityMetadataSourceService;
5 | import cn.geekview.service.CustomUserDetailsService;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 | import org.springframework.security.authentication.AuthenticationManager;
11 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
12 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
13 | import org.springframework.security.config.annotation.web.builders.WebSecurity;
14 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
15 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
16 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
17 | import org.springframework.security.web.access.AccessDeniedHandlerImpl;
18 | import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
19 | import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
20 | import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
21 | import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
22 | import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
23 |
24 | import javax.sql.DataSource;
25 |
26 |
27 | @Configuration
28 | @EnableWebSecurity
29 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
30 |
31 |
32 | @Autowired
33 | private CustomUserDetailsService customUserDetailsService;
34 |
35 | // @Autowired
36 | // private MyFilterSecurityInterceptor myFilterSecurityInterceptor;
37 |
38 | @Override
39 | public AuthenticationManager authenticationManagerBean() throws Exception {
40 |
41 | return super.authenticationManagerBean();
42 |
43 | }
44 |
45 | @Override
46 | protected void configure(HttpSecurity http) throws Exception {
47 | http
48 | // .addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class)//在正确的位置添加我们自定义的过滤器
49 | // 重新添加拥有自己属性的过滤器;
50 | /**
51 | * 不使用自定义过滤器类的话,可以直接使用默认实现的类,并提供自定义的属性
52 | */
53 | .addFilter(filterSecurityInterceptor())
54 | .authorizeRequests()
55 | //路径/home不需要验证
56 | .antMatchers("/home").permitAll()
57 | //任何请求都需要授权
58 | .anyRequest().authenticated()
59 | // .expressionHandler(new DefaultWebSecurityExpressionHandler())作用是什么?
60 | .and()
61 | .formLogin()
62 | .loginPage("/login")//之所以加true 是因为 th:if{param.error} 会去读取浏览器地址携带的参数,有了true之后,if就成立,所以后面的th:text就能执行。
63 | .permitAll()
64 | //登录成功处理
65 | .successHandler(loginSuccessHandler())
66 | .and()
67 | .logout()
68 | .permitAll()
69 | //注销后使session相关信息无效
70 | .invalidateHttpSession(true)
71 | .and()
72 | // 开启rememberme功能:验证,登录成功后,关闭页面,直接访问登陆后可以访问的页面
73 | .rememberMe()
74 | //持久化到数据库 如果不需要持久化到数据库,直接注释掉即可
75 | .rememberMeServices(new PersistentTokenBasedRememberMeServices("MySpringSecurityCookie",customUserDetailsService,persistentTokenRepository()))
76 | //设置有效时间
77 | .tokenValiditySeconds(7*24*60*60);
78 | //权限不足处理
79 | http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandlerImpl()).accessDeniedPage("/deny");
80 | }
81 |
82 | @Override
83 | public void configure(WebSecurity web) throws Exception {
84 | super.configure(web);
85 | }
86 |
87 | @Override
88 | protected void configure(AuthenticationManagerBuilder auth) throws Exception {
89 | //指定密码加密所使用的加密器为passwordEncoder()
90 | //需要将密码加密后写入数据库
91 | auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
92 | //不删除凭据,以便记住用户
93 | auth.eraseCredentials(false);
94 | }
95 |
96 | /**
97 | * 这种方式注入,会使用AuthenticationManagerBuilder新建一个AuthenticationManager对象,这就和下面
98 | * @Autowired
99 | private AuthenticationManager authenticationManager;
100 | 产生冲突导致报错,所以尽量使用上面的方式引入
101 |
102 | * @return
103 | */
104 | // @Autowired
105 | // public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
106 | // //指定密码加密所使用的加密器为passwordEncoder()
107 | // //需要将密码加密后写入数据库
108 | // auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
109 | // //不删除凭据,以便记住用户
110 | // auth.eraseCredentials(false);
111 | //
112 | // }
113 |
114 | @Bean
115 | public BCryptPasswordEncoder passwordEncoder() {
116 | return new BCryptPasswordEncoder(4);
117 | }
118 |
119 | @Bean
120 | public LoginSuccessHandler loginSuccessHandler(){
121 | return new LoginSuccessHandler();
122 | }
123 |
124 | @Autowired
125 | private DataSource dataSource;
126 |
127 | @Bean
128 | public PersistentTokenRepository persistentTokenRepository(){
129 | JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
130 | // 设置数据源 默认使用的Apache的连接池
131 | jdbcTokenRepository.setDataSource(dataSource);
132 | // 设置初始化存储Token的表 方便调试 由于源码没有对数据库中是否有表结构做出判断,正常使用的时候不建议开启,不然第二次启动会报错!
133 | // jdbcTokenRepository.setCreateTableOnStartup(true);
134 | return jdbcTokenRepository;
135 | }
136 |
137 | @Autowired
138 | private CustomInvocationSecurityMetadataSourceService mySecurityMetadataSource;
139 |
140 | @Autowired
141 | private CustomAccessDecisionManager myAccessDecisionManager;
142 |
143 | @Autowired
144 | private AuthenticationManager authenticationManager;
145 |
146 | @Bean
147 | public FilterSecurityInterceptor filterSecurityInterceptor(){
148 | FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
149 | filterSecurityInterceptor.setSecurityMetadataSource(mySecurityMetadataSource);
150 | filterSecurityInterceptor.setAccessDecisionManager(myAccessDecisionManager);
151 | filterSecurityInterceptor.setAuthenticationManager(authenticationManager);
152 | return filterSecurityInterceptor;
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/controller/BasicController.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.controller;
2 |
3 | import org.springframework.stereotype.Controller;
4 | import org.springframework.web.bind.annotation.RequestMapping;
5 |
6 | @Controller
7 | public class BasicController {
8 |
9 | @RequestMapping(value = {"/","/home"})
10 | public String home(){
11 | return "home";
12 | }
13 |
14 | @RequestMapping(value = {"/admin"})
15 | public String admin(){
16 | return "admin";
17 | }
18 |
19 | @RequestMapping(value = {"/user"})
20 | public String user(){
21 | return "user";
22 | }
23 |
24 | @RequestMapping(value = {"/vip"})
25 | public String vip(){
26 | return "vip";
27 | }
28 | @RequestMapping(value = {"/login"})
29 | public String login(){
30 | return "login";
31 | }
32 |
33 | @RequestMapping(value = {"/super"})
34 | public String superm(){
35 | return "super";
36 | }
37 | @RequestMapping(value = {"/deny"})
38 | public String deny(){
39 | return "deny";
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/entity/model/SysResource.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | import javax.persistence.*;
4 |
5 | /**
6 | * 资源类:本实例指的是访问路径
7 | */
8 | @Entity
9 | public class SysResource {
10 | @Id
11 | @GeneratedValue(strategy= GenerationType.IDENTITY)
12 | @Column (name="id",length=10)
13 | private Integer id;
14 |
15 | @Column(name="resourceName",length=1000)
16 | private String resourceName;
17 |
18 | public int getId() {
19 | return id;
20 | }
21 |
22 | public void setId(int id) {
23 | this.id = id;
24 | }
25 |
26 | public void setId(Integer id) {
27 | this.id = id;
28 | }
29 |
30 | public String getResourceName() {
31 | return resourceName;
32 | }
33 |
34 | public void setResourceName(String resourceName) {
35 | this.resourceName = resourceName;
36 | }
37 |
38 | @Override
39 | public String toString() {
40 | return "SysResource{" +
41 | "id=" + id +
42 | ", resourceName='" + resourceName + '\'' +
43 | '}';
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/entity/model/SysResourceRole.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | import javax.persistence.*;
4 | import java.util.Date;
5 |
6 | /**
7 | * 资源与角色中间表
8 | */
9 | @Entity
10 | public class SysResourceRole {
11 | @Id
12 | @GeneratedValue(strategy= GenerationType.IDENTITY)
13 | @Column (name="id",length=10)
14 | private int id;
15 |
16 | @Column(name="roleId",length=50)
17 | private String roleId;
18 |
19 | @Column(name="resourceId",length=50)
20 | private String resourceId;
21 |
22 |
23 | public int getId() {
24 | return id;
25 | }
26 |
27 | public void setId(int id) {
28 | this.id = id;
29 | }
30 |
31 | public String getRoleId() {
32 | return roleId;
33 | }
34 |
35 | public void setRoleId(String roleId) {
36 | this.roleId = roleId;
37 | }
38 |
39 | public String getResourceId() {
40 | return resourceId;
41 | }
42 |
43 | public void setResourceId(String resourceId) {
44 | this.resourceId = resourceId;
45 | }
46 |
47 | @Override
48 | public String toString() {
49 | return "SysResourceRole{" +
50 | "id=" + id +
51 | ", roleId='" + roleId + '\'' +
52 | ", resourceId='" + resourceId + '\'' +
53 | '}';
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/entity/model/SysRole.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | import javax.persistence.*;
4 |
5 |
6 | /**
7 | * 角色类
8 | */
9 | @Entity
10 | public class SysRole {
11 | @Id
12 | @GeneratedValue(strategy= GenerationType.IDENTITY)
13 | @Column (name="id",length=10)
14 | private Integer id;
15 |
16 | @Column(name="roleName",length=100)
17 | private String roleName;
18 |
19 | public Integer getId() {
20 | return id;
21 | }
22 |
23 | public void setId(Integer id) {
24 | this.id = id;
25 | }
26 |
27 | public String getRoleName() {
28 | return roleName;
29 | }
30 |
31 | public void setRoleName(String roleName) {
32 | this.roleName = roleName;
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | return "SysRole{" +
38 | "id=" + id +
39 | ", roleName='" + roleName + '\'' +
40 | '}';
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/entity/model/SysUser.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | import org.springframework.security.core.GrantedAuthority;
4 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
5 | import org.springframework.security.core.userdetails.UserDetails;
6 |
7 | import javax.persistence.*;
8 | import java.util.*;
9 |
10 | /**
11 | * 用户类
12 | */
13 | @Entity
14 | public class SysUser implements UserDetails {
15 |
16 | @Id
17 | @GeneratedValue(strategy = GenerationType.IDENTITY)
18 | @Column(name = "id", unique = true, nullable = false)
19 | private Integer id;
20 | @Column(name = "username", length = 120)
21 | private String username;
22 |
23 | @Column(name = "password", length = 120)
24 | private String password;
25 |
26 | @ManyToMany(cascade = CascadeType.REFRESH,fetch = FetchType.EAGER)
27 | private List roles;
28 |
29 | public SysUser() {
30 | }
31 |
32 | @Override
33 | public boolean isAccountNonExpired() {
34 | return true;
35 | }
36 |
37 | @Override
38 | public boolean isAccountNonLocked() {
39 | return true;
40 | }
41 |
42 | @Override
43 | public boolean isCredentialsNonExpired() {
44 | return true;
45 | }
46 |
47 | @Override
48 | public boolean isEnabled() {
49 | return true;
50 | }
51 |
52 |
53 | @Override
54 | public Collection extends GrantedAuthority> getAuthorities() {
55 | Collection authorities = new ArrayList<>();
56 | List userRoles = this.getRoles();
57 | if(userRoles != null){
58 | for (SysRole role : userRoles) {
59 | SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getRoleName());
60 | authorities.add(authority);
61 | }
62 | }
63 | return authorities;
64 | }
65 |
66 | public Integer getId() {
67 | return this.id;
68 | }
69 |
70 | public void setId(Integer id) {
71 | this.id = id;
72 | }
73 |
74 | public void setUsername(String username) {
75 | this.username = username;
76 | }
77 |
78 | public String getUsername() {
79 | return username;
80 | }
81 |
82 | public String getPassword() {
83 | return this.password;
84 | }
85 |
86 | public void setPassword(String password) {
87 | this.password = password;
88 | }
89 |
90 | public List getRoles() {
91 | return roles;
92 | }
93 |
94 | public void setRoles(List roles) {
95 | this.roles = roles;
96 | }
97 |
98 | @Override
99 | public String toString() {
100 | return "SysUser{" +
101 | "id=" + id +
102 | ", username='" + username + '\'' +
103 | ", password='" + password + '\'' +
104 | '}';
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/entity/repository/SysResourceRepository.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.repository;
2 |
3 | import cn.geekview.entity.model.SysResource;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.data.jpa.repository.Query;
6 |
7 | import java.util.List;
8 |
9 | public interface SysResourceRepository extends JpaRepository {
10 |
11 | /**
12 | * 通过角色名称获取资源列表
13 | * @param rolename
14 | * @return
15 | *
16 | */
17 | @Query(value = "SELECT * FROM sys_resource WHERE id IN ( SELECT resource_id FROM sys_resource_role WHERE role_id = ( SELECT id FROM sys_role WHERE role_name = ?1))",nativeQuery = true)
18 | List findByRoleName(String rolename);
19 | }
20 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/entity/repository/SysRoleRepository.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.repository;
2 |
3 | import cn.geekview.entity.model.SysRole;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | import java.util.List;
7 |
8 | public interface SysRoleRepository extends JpaRepository{
9 |
10 | @Override
11 | List findAll();
12 | }
13 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/entity/repository/SysUserRepository.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.repository;
2 |
3 | import cn.geekview.entity.model.SysUser;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface SysUserRepository extends JpaRepository {
7 |
8 | SysUser findByUsername(String username);
9 | }
10 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/service/CustomAccessDecisionManager.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.service;
2 |
3 | import org.springframework.security.access.AccessDecisionManager;
4 | import org.springframework.security.access.AccessDeniedException;
5 | import org.springframework.security.access.ConfigAttribute;
6 | import org.springframework.security.access.SecurityConfig;
7 | import org.springframework.security.authentication.InsufficientAuthenticationException;
8 | import org.springframework.security.core.Authentication;
9 | import org.springframework.security.core.GrantedAuthority;
10 | import org.springframework.stereotype.Service;
11 |
12 | import java.util.Collection;
13 | import java.util.Iterator;
14 |
15 | /**
16 | *AccessdecisionManager在Spring security中是很重要的。
17 | *
18 | *在验证部分简略提过了,所有的Authentication实现需要保存在一个GrantedAuthority对象数组中。
19 | *这就是赋予给主体的权限。 GrantedAuthority对象通过AuthenticationManager
20 | *保存到 Authentication对象里,然后从AccessDecisionManager读出来,进行授权判断。
21 | *
22 | *Spring Security提供了一些拦截器,来控制对安全对象的访问权限,例如方法调用或web请求。
23 | *一个是否允许执行调用的预调用决定,是由AccessDecisionManager实现的。
24 | *这个 AccessDecisionManager 被AbstractSecurityInterceptor调用,
25 | *它用来作最终访问控制的决定。 这个AccessDecisionManager接口包含三个方法:
26 | *
27 | void decide(Authentication authentication, Object secureObject,List config) throws AccessDeniedException;
28 | boolean supports(ConfigAttribute attribute);
29 | boolean supports(Class clazz);
30 |
31 | 从第一个方法可以看出来,AccessDecisionManager使用方法参数传递所有信息,这好像在认证评估时进行决定。
32 | 特别是,在真实的安全方法期望调用的时候,传递安全Object启用那些参数。
33 | 比如,让我们假设安全对象是一个MethodInvocation。
34 | 很容易为任何Customer参数查询MethodInvocation,
35 | 然后在AccessDecisionManager里实现一些有序的安全逻辑,来确认主体是否允许在那个客户上操作。
36 | 如果访问被拒绝,实现将抛出一个AccessDeniedException异常。
37 |
38 | 这个 supports(ConfigAttribute) 方法在启动的时候被
39 | AbstractSecurityInterceptor调用,来决定AccessDecisionManager
40 | 是否可以执行传递ConfigAttribute。
41 | supports(Class)方法被安全拦截器实现调用,
42 | 包含安全拦截器将显示的AccessDecisionManager支持安全对象的类型。
43 | */
44 | @Service
45 | public class CustomAccessDecisionManager implements AccessDecisionManager {
46 |
47 | //这里验证完了之后,抛出的异常,想要捕捉,需要ExceptionTranslationFilter来进行处理
48 | public void decide( Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException{
49 | if( configAttributes == null ) {
50 | return ;
51 | }
52 | Iterator iterator = configAttributes.iterator();
53 | while( iterator.hasNext()){
54 | ConfigAttribute configAttribute = iterator.next();
55 | String needRole = ((SecurityConfig)configAttribute).getAttribute();
56 | //grantedAuthority 为用户所被赋予的权限。 needRole 为访问相应的资源应该具有的权限。
57 | for( GrantedAuthority grantedAuthority: authentication.getAuthorities()){
58 | if(needRole.trim().equals(grantedAuthority.getAuthority().trim())){
59 | return;
60 | }
61 | }
62 | }
63 | /**
64 | * 如果一个AccessDeniedException被抛出并且用户已经被认证,那么这意味着一个操作已经尝试了它们不具有足够的权限。
65 | * 在这种情况下,ExceptionTranslationFilter将调用第二策略,AccessDeniedHandler。
66 | * 默认情况下,AccessDeniedHandlerImpl被使用,这只是发送一个403(禁止)响应于客户端。
67 | * 此外,还可以配置明确的实例,并设置一个错误页面的URL,它会请求转发 .
68 | * 这可以是一个简单的“拒绝访问”页上,如一个JSP,或者它可以是更复杂的处理程序,如一个MVC的控制器。
69 | * 当然,你可以自己实现接口,并使用自己的实现。
70 | */
71 | throw new AccessDeniedException("权限不足");
72 | }
73 |
74 | public boolean supports( ConfigAttribute attribute ){
75 | return true;//都要设为true
76 |
77 | }
78 |
79 | public boolean supports(Class> clazz){
80 | return true;//都要设为true
81 | }
82 |
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/service/CustomInvocationSecurityMetadataSourceService.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.service;
2 |
3 | import cn.geekview.entity.model.SysResource;
4 | import cn.geekview.entity.model.SysRole;
5 | import cn.geekview.entity.repository.SysResourceRepository;
6 | import cn.geekview.entity.repository.SysRoleRepository;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.security.access.ConfigAttribute;
9 | import org.springframework.security.access.SecurityConfig;
10 | import org.springframework.security.web.FilterInvocation;
11 | import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
12 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
13 | import org.springframework.security.web.util.matcher.RequestMatcher;
14 | import org.springframework.stereotype.Service;
15 |
16 | import javax.annotation.PostConstruct;
17 | import java.util.*;
18 |
19 |
20 | /**
21 | * 最核心的地方,就是提供某个资源对应的权限定义,即getAttributes方法返回的结果。 此类在初始化时,应该取到所有资源及其对应角色的定义。
22 | */
23 | @Service
24 | public class CustomInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {
25 |
26 | @Autowired
27 | private SysRoleRepository roleRepository;
28 |
29 | @Autowired
30 | private SysResourceRepository resourceRepository;
31 |
32 | private static Map> resourceMap = null;
33 |
34 | /*public CustomInvocationSecurityMetadataSourceService(SResourceService sres,SRoleService sR) {
35 | this.sResourceService = sres;
36 | this.sRoleService = sR;
37 | loadResourceDefine();
38 | }*/
39 |
40 | /**
41 | * 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。
42 | * PostConstruct在构造函数之后执行,init()方法之前执行。
43 | * 此处一定要加上@PostConstruct注解
44 | *
45 | * 注意: 形成以URL为Key,权限列表为Value的Map时,注意Key和Value的对应性,
46 | * 避免Value的不正确对应形成重复,这样会导致没有权限的也能访问到不该访问的资源
47 | */
48 | @PostConstruct
49 | private void loadResourceDefine() {
50 | // 在Web服务器启动时,提取系统中的所有权限。
51 | List roleList =roleRepository.findAll();
52 |
53 | List roleNameList = new ArrayList();
54 | if(roleList!=null && roleList.size()>0) {
55 | for (SysRole role : roleList) {
56 | roleNameList.add(role.getRoleName());
57 | }
58 | }
59 | /*
60 | * 应当是资源为key, 权限为value。 资源通常为url, 权限就是那些以ROLE_为前缀的角色。
61 | * 一个资源可以由多个权限来访问。
62 | *
63 | */
64 | resourceMap = new HashMap>();
65 | for (String roleName : roleNameList) {
66 | // 将角色名封装一个安全配置???这样理解有点不准确, 说白了就是一个角色名,只是为了和框架整合换一种说法
67 | ConfigAttribute configAttribute = new SecurityConfig(roleName);
68 | List urlList = new ArrayList();
69 | List resourceList = resourceRepository.findByRoleName(roleName);
70 | if(resourceList!=null && resourceList.size()>0) {//如果不加判断,这里如果 resourceRepository.findByRoleName(roleName);为null.则会报错
71 | for(SysResource resource :resourceList){
72 | urlList.add(resource.getResourceName());
73 | }
74 | }
75 | for (String res : urlList) {
76 | String url = res;
77 | /*
78 | * 判断资源文件和权限的对应关系,如果已经存在相关的资源url,
79 | * 则要通过该url为key提取出权限集合,将权限增加到权限集合中。
80 | *
81 | */
82 | if (resourceMap.containsKey(url)) {
83 | Collection value = resourceMap.get(url);
84 | value.add(configAttribute);
85 | resourceMap.put(url, value);
86 | } else {
87 | Collection atts = new ArrayList();
88 | atts.add(configAttribute);
89 | resourceMap.put(url, atts);// 一个URL对应多种角色
90 | }
91 | }
92 | }
93 |
94 | }
95 |
96 | /**
97 | * 这里这样写有问题,获取的是一个空的
98 | * @return
99 | */
100 | @Override
101 | public Collection getAllConfigAttributes() {
102 | return new ArrayList();
103 | }
104 |
105 | /**
106 | * 根据URL,找到相关的权限配置。
107 | * 要有URL.indexof("?")这样的判断,主要是对URL你问号之前的匹配,避免对用户请求带参数的URL与数据库里面的URL不匹配,造成访问拒绝
108 | */
109 | @Override
110 | public Collection getAttributes(Object object) throws IllegalArgumentException {
111 | // object 是一个URL,被用户请求的url。
112 | FilterInvocation filterInvocation = (FilterInvocation) object;
113 | if (resourceMap == null) {
114 | loadResourceDefine();
115 | }
116 | Iterator iterator = resourceMap.keySet().iterator();
117 | while (iterator.hasNext()) {
118 | String resURL = iterator.next();
119 | // 优化请求路径后面带参数的部分
120 | RequestMatcher requestMatcher = new AntPathRequestMatcher(resURL);
121 | if(requestMatcher.matches(filterInvocation.getHttpRequest())) {
122 | return resourceMap.get(resURL);
123 | }
124 | }
125 | return null;
126 | }
127 | @Override
128 | public boolean supports(Class> arg0) {
129 | return true;
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/java/cn/geekview/service/CustomUserDetailsService.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.service;
2 |
3 | import cn.geekview.entity.model.SysUser;
4 | import cn.geekview.entity.repository.SysUserRepository;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.security.core.userdetails.UserDetails;
7 | import org.springframework.security.core.userdetails.UserDetailsService;
8 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
9 | import org.springframework.stereotype.Component;
10 |
11 | @Component
12 | public class CustomUserDetailsService implements UserDetailsService {
13 |
14 | @Autowired
15 | private SysUserRepository userReporitory;
16 |
17 | @Override
18 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
19 | //SysUser对应数据库中的用户表,是最终存储用户和密码的表,可自定义
20 | //本例使用SysUser中的name作为用户名:
21 | SysUser user = userReporitory.findByUsername(username);
22 | if (user == null) {
23 | throw new UsernameNotFoundException("UserName " + username + " not found");
24 | }
25 | return user;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScnuWang/SpringBoot/dab0a4c95389a69f3dbaadb09d28741e4d706c66/springsecurity2/src/main/resources/application.properties
--------------------------------------------------------------------------------
/springsecurity2/src/main/resources/templates/admin.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ADMIN
5 |
6 |
7 |
8 | 这里是ADMIN页面!!!!!
9 |
10 | 访问:
11 | 首页
12 | 普通用户页面
13 | VIP用户页面
14 | 管理员页面
15 | 超级管理员页面
16 |
17 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/resources/templates/deny.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403
5 |
6 |
7 |
8 |
9 | 请求异常信息:
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/resources/templates/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | HOME
5 |
6 |
7 |
8 | 这里是首页!!!
9 |
10 |
11 |
14 |
15 | 访问:
16 | 首页
17 | 普通用户页面
18 | VIP用户页面
19 | 管理员页面
20 | 超级管理员页面
21 |
22 |
23 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/resources/templates/login.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | Spring Security Example
6 |
7 |
8 |
9 | 用户名和密码不正确
10 |
11 |
12 | 注销成功
13 |
14 |
20 |
21 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/resources/templates/super.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SUPER
5 |
6 |
7 |
8 |
9 | 这里是SUPER用户的页面!!!
10 |
11 | 访问:
12 | 首页
13 | 普通用户页面
14 | VIP用户页面
15 | 管理员页面
16 | 超级管理员页面
17 |
18 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/resources/templates/user.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | USER
5 |
6 |
7 |
8 | 这里是普通注册用户的页面!!!
9 | 访问:
10 | 首页
11 | 普通用户页面
12 | VIP用户页面
13 | 管理员页面
14 | 超级管理员页面
15 |
16 |
17 |
--------------------------------------------------------------------------------
/springsecurity2/src/main/resources/templates/vip.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | VIP
5 |
6 |
7 |
8 |
9 | 这里是VIP页面!!!
10 |
11 | 访问:
12 | 首页
13 | 普通用户页面
14 | VIP用户页面
15 | 管理员页面
16 | 超级管理员页面
17 |
18 |
--------------------------------------------------------------------------------
/springsecurity2/src/test/java/cn/geekview/BasicTest.java:
--------------------------------------------------------------------------------
1 | package cn.geekview;
2 |
3 | import org.junit.Test;
4 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
5 |
6 | public class BasicTest {
7 |
8 | @Test
9 | public void test(){
10 | BCryptPasswordEncoder bc=new BCryptPasswordEncoder(4);//将密码加密
11 | System.out.println("密码:"+ bc.encode("123456"));
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/springsecurity2/src/test/java/cn/geekview/Springsecurity2ApplicationTests.java:
--------------------------------------------------------------------------------
1 | package cn.geekview;
2 |
3 | import cn.geekview.entity.repository.SysResourceRepository;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.test.context.junit4.SpringRunner;
9 |
10 | @RunWith(SpringRunner.class)
11 | @SpringBootTest
12 | public class Springsecurity2ApplicationTests {
13 |
14 | @Autowired
15 | private SysResourceRepository resourceRepository;
16 |
17 | @Test
18 | public void contextLoads() {
19 | System.out.println(resourceRepository.findByRoleName("VIP"));
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/springsecurity3/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | ### STS ###
5 | .apt_generated
6 | .classpath
7 | .factorypath
8 | .project
9 | .settings
10 | .springBeans
11 |
12 | ### IntelliJ IDEA ###
13 | .idea
14 | *.iws
15 | *.iml
16 | *.ipr
17 |
18 | ### NetBeans ###
19 | nbproject/private/
20 | build/
21 | nbbuild/
22 | dist/
23 | nbdist/
24 | .nb-gradle/
--------------------------------------------------------------------------------
/springsecurity3/README.md:
--------------------------------------------------------------------------------
1 | ### 注册
2 | 知识点复习:
3 |
4 | JPA相关
5 |
6 | 流程:
7 |
8 | 首页--》注册--》填写基本信息--》提交表单--》
9 | 持久化基本信息到数据库、发送验证邮件--》
10 | 邮箱验证--》登录页登录
11 |
12 | 需求:
13 |
14 | 1、所有必填字段是否都已填写(无空白字段或 null 字段)
15 | 2、电子邮件地址是否有效(格式是否正确)
16 | 3、密码确认字段与密码字段是否匹配(前端匹配,后端不需要)
17 | 4、帐户是否已经注册
18 | 5、为每个用户生成校验Token,并持久化
19 | 6、给注册邮箱发送带有校验Token的邮件
20 | 7、密码强度校验提示
21 | 8、注册登录都使用HMAC 算法校验
--------------------------------------------------------------------------------
/springsecurity3/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Migwn, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | echo $MAVEN_PROJECTBASEDIR
205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
206 |
207 | # For Cygwin, switch paths to Windows format before running java
208 | if $cygwin; then
209 | [ -n "$M2_HOME" ] &&
210 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
211 | [ -n "$JAVA_HOME" ] &&
212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
213 | [ -n "$CLASSPATH" ] &&
214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
215 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
217 | fi
218 |
219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
220 |
221 | exec "$JAVACMD" \
222 | $MAVEN_OPTS \
223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
226 |
--------------------------------------------------------------------------------
/springsecurity3/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/springsecurity3/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | cn.geekview
7 | springsecurity3
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | springsecurity3
12 | Module for Spring Boot With Spring Security For Registeration Process
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.5.9.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-data-jpa
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-security
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-thymeleaf
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-web
43 |
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-devtools
48 | runtime
49 |
50 |
51 | mysql
52 | mysql-connector-java
53 | runtime
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-test
58 | test
59 |
60 |
61 | org.springframework.security
62 | spring-security-test
63 | test
64 |
65 |
66 | org.projectlombok
67 | lombok
68 | compile
69 |
70 |
71 | org.springframework.boot
72 | spring-boot-starter-mail
73 |
74 |
75 |
76 |
77 |
78 |
79 | org.springframework.boot
80 | spring-boot-maven-plugin
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/Springsecurity3Application.java:
--------------------------------------------------------------------------------
1 | package cn.geekview;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class Springsecurity3Application {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(Springsecurity3Application.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/annotation/EmailValidator.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.annotation;
2 |
3 | import javax.validation.ConstraintValidator;
4 | import javax.validation.ConstraintValidatorContext;
5 | import java.util.regex.Matcher;
6 | import java.util.regex.Pattern;
7 |
8 | /**
9 | * 邮箱校验:由于 org.hibernate.validator.constraints.Email的注解校验不能识别:abc@abc这种邮箱地址
10 | */
11 | public class EmailValidator implements ConstraintValidator {
12 |
13 | private Pattern pattern;
14 | private Matcher matcher;
15 | private static final String EMAIL_PATTERN = "[A-Za-z0-9._%-+]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
16 | @Override
17 | public void initialize(ValidEmail constraintAnnotation) {
18 | }
19 | @Override
20 | public boolean isValid(String email, ConstraintValidatorContext context){
21 | return (validateEmail(email));
22 | }
23 | private boolean validateEmail(String email) {
24 | pattern = Pattern.compile(EMAIL_PATTERN);
25 | matcher = pattern.matcher(email);
26 | return matcher.matches();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/annotation/ValidEmail.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.annotation;
2 |
3 | import javax.validation.Constraint;
4 | import javax.validation.Payload;
5 | import java.lang.annotation.Documented;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.Target;
8 |
9 | import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
10 | import static java.lang.annotation.ElementType.FIELD;
11 | import static java.lang.annotation.ElementType.TYPE;
12 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
13 |
14 | @Target({TYPE, FIELD, ANNOTATION_TYPE})
15 | @Retention(RUNTIME)
16 | @Constraint(validatedBy = EmailValidator.class)
17 | @Documented
18 | public @interface ValidEmail {
19 | String message() default "Invalid email";
20 | Class>[] groups() default {};
21 | Class extends Payload>[] payload() default {};
22 | }
23 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/config/WebSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config;
2 |
3 | import cn.geekview.service.impl.UserServiceImpl;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
11 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
12 | import org.springframework.security.crypto.password.PasswordEncoder;
13 |
14 | @Configuration
15 | @EnableWebSecurity
16 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
17 |
18 | @Autowired
19 | private UserServiceImpl userService;
20 |
21 | @Override
22 | protected void configure(AuthenticationManagerBuilder auth) throws Exception {
23 | //注册自己的UserService
24 | auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
25 | }
26 |
27 | @Override
28 | protected void configure(HttpSecurity http) throws Exception {
29 | //所有请求都允许访问
30 | http.authorizeRequests().anyRequest().permitAll().and().csrf().disable();
31 | }
32 |
33 | @Bean
34 | public PasswordEncoder passwordEncoder(){
35 | return new BCryptPasswordEncoder();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/controller/IndexController.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.controller;
2 |
3 | import org.springframework.stereotype.Controller;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 |
6 | @Controller
7 | public class IndexController {
8 |
9 | @GetMapping("/login")
10 | public String login(){
11 | return "login";
12 | }
13 |
14 | @GetMapping("/regist")
15 | public String regist(){
16 | return "regist";
17 | }
18 |
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/controller/RegistrationController.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.controller;
2 |
3 | import cn.geekview.entity.model.User;
4 | import cn.geekview.entity.model.VerificationToken;
5 | import cn.geekview.service.IUserService;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Controller;
8 | import org.springframework.ui.Model;
9 | import org.springframework.web.bind.annotation.GetMapping;
10 | import org.springframework.web.bind.annotation.RequestParam;
11 | import org.springframework.web.context.request.WebRequest;
12 |
13 | import java.util.Calendar;
14 |
15 | @Controller
16 | public class RegistrationController {
17 | @Autowired
18 | private IUserService service;
19 |
20 | @GetMapping(value = "/regitrationConfirm")
21 | public String confirmRegistration (WebRequest request, Model model, @RequestParam("token") String token) {
22 |
23 | VerificationToken verificationToken = service.getVerificationToken(token);
24 | //验证令牌不存在
25 | if (verificationToken == null) {
26 | model.addAttribute("message", "验证令牌不存在!!!");
27 | return "redirect:/emailError.html";
28 | }
29 | User user = verificationToken.getUser();
30 | Calendar cal = Calendar.getInstance();
31 | if ((verificationToken.getExpiryDate().getTime() - cal.getTime().getTime()) <= 0) {
32 | model.addAttribute("message", "验证令牌已过期!!!");
33 | return "redirect:/emailError.html";
34 | }
35 | user.setEnabled(true);
36 | service.saveRegisteredUser(user);
37 | return "redirect:/login";//这样直接重定向的路径需要在Controller的路径上存在的路径不然会报错!!!
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.controller;
2 |
3 | import cn.geekview.entity.model.User;
4 | import cn.geekview.event.OnRegistrationCompleteEvent;
5 | import cn.geekview.service.IUserService;
6 | import cn.geekview.service.impl.UserServiceImpl;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.context.ApplicationEventPublisher;
10 | import org.springframework.http.HttpRequest;
11 | import org.springframework.stereotype.Controller;
12 | import org.springframework.ui.Model;
13 | import org.springframework.validation.BindingResult;
14 | import org.springframework.web.bind.annotation.RequestMapping;
15 | import org.springframework.web.bind.annotation.RequestMethod;
16 | import org.springframework.web.context.request.WebRequest;
17 | import org.springframework.web.servlet.ModelAndView;
18 |
19 | import javax.validation.Valid;
20 |
21 | @Controller
22 | @Slf4j
23 | public class UserController {
24 |
25 | @Autowired
26 | private ApplicationEventPublisher eventPublisher;
27 |
28 | @Autowired
29 | private IUserService userService;
30 |
31 | @RequestMapping(value = {"/","/home"})
32 | public String home(){
33 | return "home";
34 | }
35 |
36 | @RequestMapping(value = {"/login"})
37 | public String login(){
38 | return "login";
39 | }
40 |
41 | @RequestMapping(value = {"/register"})
42 | public String register(Model model){
43 | return "register";
44 | }
45 |
46 | /**
47 | * @Valid的参数后必须紧挨着一个BindingResult 参数,否则spring会在校验不通过时直接抛出异常
48 | * @param user
49 | * @param result
50 | * @return
51 | */
52 | @RequestMapping(value = "/registration", method = RequestMethod.POST)
53 | public ModelAndView registerUserAccount (@Valid User user, BindingResult result, WebRequest request) {
54 |
55 | if (result.hasErrors()) {
56 | return new ModelAndView("register", "user", user);
57 | }
58 |
59 | User registered = createUserAccount(user);
60 | if (registered == null) {
61 | result.reject("emailError","该邮箱已经注册!!!");
62 | return new ModelAndView("register", "message", "该邮箱已经注册!!!");
63 | }
64 | // 发布注册完成事件
65 | try {
66 | String appUrl = request.getContextPath();
67 | eventPublisher.publishEvent(new OnRegistrationCompleteEvent (registered, appUrl));
68 | } catch (Exception me) {
69 | return new ModelAndView("emailError", "message", "邮件发送异常,请检查您的邮箱地址是否正确");
70 | }
71 | return new ModelAndView("home", "user", user);
72 | }
73 |
74 | private User createUserAccount(User user) {
75 | User registered = null;
76 | try {
77 | registered = userService.registerNewUserAccount(user);
78 | } catch (Exception e) {
79 | return null;
80 | }
81 | return registered;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/entity/model/Resource.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | import javax.persistence.*;
4 | import java.util.HashSet;
5 | import java.util.Set;
6 |
7 | @Entity
8 | @Table(name = "t_resource")
9 | public class Resource {
10 |
11 | @Id
12 | @GeneratedValue
13 | private Integer id;
14 |
15 | private String name;//资源名称
16 |
17 | @ManyToMany(mappedBy = "resources",cascade = CascadeType.ALL,fetch = FetchType.LAZY)
18 | private Set roles = new HashSet<>();//一个资源可以被多个角色调用
19 | }
20 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/entity/model/Role.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | import lombok.Data;
4 |
5 | import javax.persistence.*;
6 | import java.util.HashSet;
7 | import java.util.List;
8 | import java.util.Set;
9 |
10 | @Data
11 | @Entity
12 | @Table(name = "t_role")
13 | public class Role {
14 | @Id
15 | @GeneratedValue
16 | private Integer id;
17 |
18 | private String name;//角色名称
19 |
20 | /**
21 | * mappedBy:声明于关系的被维护方,声明的值为关系的维护方的关系对象属性名。
22 | * 被维护方不会主动去维护关联关系,真正的关系维护,掌握在维护方的手中。
23 | * cascade:级联关系,给当前设置的实体操作另一个实体的权限,不要随便给all权限操作,应该根据业务需求选择所需的级联关系.
24 | * 更多解释:https://www.jianshu.com/p/e8caafce5445
25 | */
26 | @ManyToMany(mappedBy = "roles",cascade = {CascadeType.MERGE,CascadeType.DETACH},fetch = FetchType.LAZY)
27 | private Set users = new HashSet<>();//一个角色可以有多个用户
28 |
29 | @ManyToMany(cascade = CascadeType.DETACH,fetch = FetchType.LAZY)
30 | private Set resources = new HashSet<>();//一个角色可以调用多个资源
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/entity/model/User.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | import cn.geekview.annotation.ValidEmail;
4 | import lombok.Data;
5 | import org.hibernate.validator.constraints.NotEmpty;
6 | import org.springframework.security.core.GrantedAuthority;
7 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
8 | import org.springframework.security.core.userdetails.UserDetails;
9 |
10 | import javax.persistence.*;
11 | import javax.validation.constraints.NotNull;
12 | import java.util.Collection;
13 | import java.util.HashSet;
14 | import java.util.Set;
15 |
16 |
17 | @Data
18 | @Entity
19 | @Table(name = "t_user")
20 | public class User implements UserDetails{
21 |
22 | @Id
23 | @GeneratedValue(strategy = GenerationType.AUTO)
24 | private Integer id;//主键
25 |
26 | @NotNull
27 | @NotEmpty
28 | private String username;//用户名
29 |
30 | @NotNull
31 | @NotEmpty
32 | private String password;//密码
33 |
34 | @NotNull
35 | @NotEmpty
36 | @ValidEmail
37 | private String email;//邮箱
38 |
39 | private boolean enabled;//是否激活
40 |
41 | /**
42 | * CascadeType.DETACH
43 | Cascade detach operation,级联脱管/游离操作。
44 | 如果你要删除一个实体,但是它有外键无法删除,你就需要这个级联权限了。它会撤销所有相关的外键关联。
45 | */
46 | @ManyToMany(cascade = CascadeType.DETACH,fetch = FetchType.LAZY)
47 | private Set roles = new HashSet<>();
48 |
49 | public User(){
50 | super();
51 | this.enabled=false;
52 | }
53 |
54 | // 获取用户有哪些角色(对应框架就是有哪些权限)
55 | @Override
56 | public Collection extends GrantedAuthority> getAuthorities() {
57 | Collection grantedAuthorities = new HashSet<>();
58 | Set roles = this.roles;
59 | if (roles != null) {
60 | for (Role role : roles) {
61 | SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getName());
62 | grantedAuthorities.add(grantedAuthority);
63 | }
64 | }
65 | return grantedAuthorities;
66 | }
67 |
68 | @Override
69 | public boolean isAccountNonExpired() {
70 | return true;
71 | }
72 |
73 | @Override
74 | public boolean isAccountNonLocked() {
75 | return true;
76 | }
77 |
78 | @Override
79 | public boolean isCredentialsNonExpired() {
80 | return true;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/entity/model/VerificationToken.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.model;
2 |
3 | import lombok.Data;
4 |
5 | import javax.persistence.*;
6 | import java.sql.Timestamp;
7 | import java.util.Calendar;
8 | import java.util.Date;
9 |
10 | @Data
11 | @Entity
12 | public class VerificationToken {
13 | private static final int EXPIRATION = 60 * 24;
14 |
15 | @Id
16 | @GeneratedValue(strategy = GenerationType.AUTO)
17 | private Long id;
18 |
19 | private String token;
20 |
21 | @OneToOne(targetEntity = User.class, fetch = FetchType.EAGER)
22 | @JoinColumn(nullable = false, name = "user_id")
23 | private User user;
24 |
25 | private Date expiryDate;
26 |
27 | private Date calculateExpiryDate(int expiryTimeInMinutes) {
28 | Calendar cal = Calendar.getInstance();
29 | cal.setTime(new Timestamp(cal.getTime().getTime()));
30 | cal.add(Calendar.MINUTE, expiryTimeInMinutes);
31 | return new Date(cal.getTime().getTime());
32 | }
33 | public VerificationToken(){
34 |
35 | }
36 | public VerificationToken(String token , User user){
37 | this.user = user;
38 | this.token=token;
39 | this.expiryDate=this.calculateExpiryDate(this.EXPIRATION);
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/entity/repository/UserRepository.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.repository;
2 |
3 | import cn.geekview.entity.model.User;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface UserRepository extends JpaRepository {
7 |
8 | User findByEmail(String email);
9 |
10 | User findByUsername(String username);
11 | }
12 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/entity/repository/VerificationTokenRepository.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.entity.repository;
2 |
3 | import cn.geekview.entity.model.User;
4 | import cn.geekview.entity.model.VerificationToken;
5 | import org.springframework.data.jpa.repository.JpaRepository;
6 |
7 | public interface VerificationTokenRepository extends JpaRepository {
8 |
9 | VerificationToken findByToken(String token);
10 |
11 | VerificationToken findByUser(User user);
12 | }
13 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/event/Listener/RegistrationListener.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.event.Listener;
2 |
3 | import cn.geekview.entity.model.User;
4 | import cn.geekview.event.OnRegistrationCompleteEvent;
5 | import cn.geekview.service.IUserService;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.ApplicationListener;
8 | import org.springframework.context.MessageSource;
9 | import org.springframework.core.env.Environment;
10 | import org.springframework.mail.SimpleMailMessage;
11 | import org.springframework.mail.javamail.JavaMailSender;
12 | import org.springframework.stereotype.Component;
13 |
14 | import java.util.UUID;
15 |
16 | @Component
17 | public class RegistrationListener implements ApplicationListener {
18 | @Autowired
19 | private IUserService service;
20 |
21 | @Autowired
22 | private JavaMailSender mailSender;
23 |
24 | @Autowired
25 | private Environment env;
26 |
27 | @Override
28 | public void onApplicationEvent(final OnRegistrationCompleteEvent event) {
29 | this.confirmRegistration(event);
30 | }
31 |
32 | private void confirmRegistration(final OnRegistrationCompleteEvent event) {
33 | final User user = event.getUser();
34 | final String token = UUID.randomUUID().toString();
35 | service.createVerificationTokenForUser(user, token);
36 |
37 | final SimpleMailMessage email = constructEmailMessage(event, user, token);
38 | mailSender.send(email);
39 | }
40 |
41 |
42 | private final SimpleMailMessage constructEmailMessage(final OnRegistrationCompleteEvent event, final User user, final String token) {
43 | final String recipientAddress = user.getEmail();
44 | final String subject = "注册邮箱激活";
45 | final String confirmationUrl = event.getAppUrl() + "/regitrationConfirm?token=" + token;
46 | final SimpleMailMessage email = new SimpleMailMessage();
47 | email.setTo(recipientAddress);
48 | email.setSubject(subject);
49 | email.setText("http://localhost:80"+confirmationUrl);
50 | email.setFrom(env.getProperty("mail.from.addr"));
51 | return email;
52 | }
53 |
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/event/OnRegistrationCompleteEvent.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.event;
2 |
3 | import cn.geekview.entity.model.User;
4 | import org.springframework.context.ApplicationEvent;
5 |
6 | /**
7 | * ApplicationEvent ?????
8 | */
9 | public class OnRegistrationCompleteEvent extends ApplicationEvent {
10 |
11 | private final String appUrl;
12 | private final User user;
13 |
14 | public OnRegistrationCompleteEvent(final User user, final String appUrl) {
15 | super(user);
16 | this.user = user;
17 | this.appUrl = appUrl;
18 | }
19 |
20 | //
21 |
22 | public String getAppUrl() {
23 | return appUrl;
24 | }
25 |
26 |
27 | public User getUser() {
28 | return user;
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/service/IUserService.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.service;
2 |
3 | import cn.geekview.entity.model.User;
4 | import cn.geekview.entity.model.VerificationToken;
5 | import org.springframework.security.core.userdetails.UserDetailsService;
6 |
7 | public interface IUserService extends UserDetailsService {
8 |
9 | User findByEmail(String email);
10 |
11 | void createVerificationTokenForUser(User user,String token);
12 |
13 | VerificationToken getVerificationToken(String VerificationToken);
14 |
15 | User getUser(String verificationToken);
16 |
17 | void saveRegisteredUser(User user);
18 |
19 | User registerNewUserAccount(User user) throws Exception;
20 | }
21 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/java/cn/geekview/service/impl/UserServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.service.impl;
2 |
3 | import cn.geekview.entity.model.User;
4 | import cn.geekview.entity.model.VerificationToken;
5 | import cn.geekview.entity.repository.UserRepository;
6 | import cn.geekview.entity.repository.VerificationTokenRepository;
7 | import cn.geekview.service.IUserService;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.security.core.userdetails.UserDetails;
10 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
11 | import org.springframework.security.crypto.password.PasswordEncoder;
12 | import org.springframework.stereotype.Service;
13 |
14 | import javax.transaction.Transactional;
15 |
16 | @Service
17 | public class UserServiceImpl implements IUserService {
18 |
19 | @Autowired
20 | private UserRepository userRepository;
21 |
22 | @Autowired
23 | private VerificationTokenRepository tokenRepository;
24 |
25 | @Autowired
26 | private PasswordEncoder passwordEncoder;
27 |
28 | @Transactional
29 | public User registerNewUserAccount(User user) throws Exception {
30 | if (isEmailExist(user.getEmail())) {
31 | throw new Exception("邮箱已经注册!!!");
32 | }else {
33 | user.setPassword(passwordEncoder.encode(user.getPassword()));
34 | return userRepository.save(user);
35 | }
36 |
37 | }
38 |
39 | private boolean isEmailExist(String email) {
40 | User user = findByEmail(email);
41 | if (user != null) {
42 | return true;
43 | }
44 | return false;
45 | }
46 |
47 | @Override
48 | public User findByEmail(String email) {
49 | return userRepository.findByEmail(email);
50 | }
51 |
52 | @Override
53 | public void createVerificationTokenForUser(User user, String token) {
54 | VerificationToken myToken = new VerificationToken(token, user);
55 | tokenRepository.save(myToken);
56 | }
57 |
58 | @Override
59 | public VerificationToken getVerificationToken(String VerificationToken) {
60 | return tokenRepository.findByToken(VerificationToken);
61 | }
62 |
63 | @Override
64 | public User getUser(String verificationToken) {
65 | return tokenRepository.findByToken(verificationToken).getUser();
66 | }
67 |
68 | @Override
69 | public void saveRegisteredUser(User user) {
70 | userRepository.save(user);
71 | }
72 |
73 | @Override
74 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
75 | User user = userRepository.findByUsername(username);
76 | if (user == null) {
77 | throw new UsernameNotFoundException("用户名:"+username+" 不存在!");
78 | }
79 | return user;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScnuWang/SpringBoot/dab0a4c95389a69f3dbaadb09d28741e4d706c66/springsecurity3/src/main/resources/application.properties
--------------------------------------------------------------------------------
/springsecurity3/src/main/resources/templates/emailError.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 邮箱验证
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/resources/templates/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 首页
5 |
6 |
7 |
8 | 这里是首页!!!
9 | 注册
10 | 登录
11 |
12 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/resources/templates/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 登录
5 |
6 |
7 |
8 | 登录页面
9 |
10 |
--------------------------------------------------------------------------------
/springsecurity3/src/main/resources/templates/register.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 注册
5 |
6 |
7 |
8 | form
9 |
17 |
18 |
19 | login
20 |
21 |
--------------------------------------------------------------------------------
/springsecurity3/src/test/java/cn/geekview/Springsecurity3ApplicationTests.java:
--------------------------------------------------------------------------------
1 | package cn.geekview;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class Springsecurity3ApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/springsecurity4/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | ### STS ###
5 | .apt_generated
6 | .classpath
7 | .factorypath
8 | .project
9 | .settings
10 | .springBeans
11 |
12 | ### IntelliJ IDEA ###
13 | .idea
14 | *.iws
15 | *.iml
16 | *.ipr
17 |
18 | ### NetBeans ###
19 | nbproject/private/
20 | build/
21 | nbbuild/
22 | dist/
23 | nbdist/
24 | .nb-gradle/
--------------------------------------------------------------------------------
/springsecurity4/README.md:
--------------------------------------------------------------------------------
1 | ### 本模块集成登录注册整个流程以及对资源的访问控制
2 |
3 | 初始需求:
4 |
5 | 1、邮箱注册登录
6 | 2、邮箱激活验证
7 | 3、资源访问控制
8 | 4、密码使用BCrypt加密
9 |
10 | 需求升级:
11 |
12 | 1、OAuth授权登录 [x]
13 | 2、密码强度校验 [x]
14 | 3、HMAC校验 [x]
15 |
16 |
17 | 问题解答:
18 |
19 | 1、JPA多对多映射关系出现死循环导致内存泄露报错
20 | 答:找了大半天的问题,按照@ManyToMany源码示例配置仍然错误,最后去掉lombok的@Data注解解决问题,使用原始setter,getter。暂不知道原因???
21 |
22 | 2、AuthenticationException异常没有捕获到,即使用authenticationEntryPoint没有效果
23 | 答:用户注册之后没有激活,导致产生DisabledException,但是却没有自定义被注册的authenticationEntryPoint拦截,估计是SpringSecurity框架将这种情况当做是没有登录成功,如果不自定义登录失败的Handler默认使用SimpleUrlAuthenticationFailureHandler
24 | 跳转到login?error这种情况要获取异常信息可使用:获取异常信息
25 |
26 | 3、CSRF防御:org.springframework.security.web.csrf.InvalidCsrfTokenException: Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
27 | 答:thymeleaf 在POST表单中添加即可
28 |
29 | 如果对第三方开放接口,那么以上方式就不能用了,需要添加排除CSRF防御的列表
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/springsecurity4/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Migwn, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | echo $MAVEN_PROJECTBASEDIR
205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
206 |
207 | # For Cygwin, switch paths to Windows format before running java
208 | if $cygwin; then
209 | [ -n "$M2_HOME" ] &&
210 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
211 | [ -n "$JAVA_HOME" ] &&
212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
213 | [ -n "$CLASSPATH" ] &&
214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
215 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
217 | fi
218 |
219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
220 |
221 | exec "$JAVACMD" \
222 | $MAVEN_OPTS \
223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
226 |
--------------------------------------------------------------------------------
/springsecurity4/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/springsecurity4/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | cn.geekview
7 | springsecurity4
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | springsecurity4
12 | Demo project for Spring Boot With Spring Security For Registration And Login
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.5.9.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-data-jpa
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-mail
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-security
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-thymeleaf
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-starter-validation
47 |
48 |
49 |
50 | org.springframework.boot
51 | spring-boot-devtools
52 | runtime
53 |
54 |
55 | mysql
56 | mysql-connector-java
57 | runtime
58 |
59 |
60 | org.projectlombok
61 | lombok
62 | true
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-starter-test
67 | test
68 |
69 |
70 | org.springframework.security
71 | spring-security-test
72 | test
73 |
74 |
75 | joda-time
76 | joda-time
77 |
78 |
79 | org.springframework.security
80 | spring-security-taglibs
81 | 4.2.3.RELEASE
82 |
83 |
84 |
85 |
86 |
87 |
88 | org.springframework.boot
89 | spring-boot-maven-plugin
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/Springsecurity4Application.java:
--------------------------------------------------------------------------------
1 | package cn.geekview;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 |
7 | @SpringBootApplication
8 | @EnableAutoConfiguration
9 | public class Springsecurity4Application {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(Springsecurity4Application.class, args);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/annotation/EmailCheck.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.annotation;
2 |
3 | import javax.validation.Constraint;
4 | import java.lang.annotation.*;
5 |
6 | @Target({ElementType.FIELD})
7 | @Retention(RetentionPolicy.RUNTIME)
8 | @Constraint(validatedBy = EmailChek.class)
9 | @Documented
10 | public @interface EmailCheck {
11 |
12 | String message() default "非法邮箱地址";
13 | }
14 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/annotation/EmailChek.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.annotation;
2 |
3 | import javax.validation.ConstraintValidator;
4 | import javax.validation.ConstraintValidatorContext;
5 | import java.util.regex.Matcher;
6 | import java.util.regex.Pattern;
7 |
8 | public class EmailChek implements ConstraintValidator {
9 |
10 | private Pattern pattern;
11 | private Matcher matcher;
12 | private static final String EMAIL_PATTERN = "[A-Za-z0-9._%-+]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
13 |
14 | @Override
15 | public void initialize(EmailCheck constraintAnnotation) {
16 |
17 | }
18 |
19 | @Override
20 | public boolean isValid(String email, ConstraintValidatorContext context) {
21 | return (validateEmail(email));
22 | }
23 |
24 | private boolean validateEmail(String email) {
25 | pattern = Pattern.compile(EMAIL_PATTERN);
26 | matcher = pattern.matcher(email);
27 | return matcher.matches();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/config/security/AccessDecisionManagerImpl.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config.security;
2 |
3 | import org.springframework.security.access.AccessDecisionManager;
4 | import org.springframework.security.access.AccessDeniedException;
5 | import org.springframework.security.access.ConfigAttribute;
6 | import org.springframework.security.access.SecurityConfig;
7 | import org.springframework.security.authentication.InsufficientAuthenticationException;
8 | import org.springframework.security.core.Authentication;
9 | import org.springframework.security.core.GrantedAuthority;
10 | import org.springframework.stereotype.Component;
11 |
12 | import java.util.Collection;
13 | import java.util.Iterator;
14 |
15 | /**
16 | * 判断是否有权限
17 | */
18 | @Component
19 | public class AccessDecisionManagerImpl implements AccessDecisionManager {
20 |
21 | public void decide( Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException{
22 | if( configAttributes == null ) {
23 | return ;
24 | }
25 | Iterator iterator = configAttributes.iterator();
26 | while( iterator.hasNext()){
27 | ConfigAttribute configAttribute = iterator.next();
28 | String needRole = ((SecurityConfig)configAttribute).getAttribute();
29 | //grantedAuthority 为用户所被赋予的权限。 needRole 为访问相应的资源应该具有的权限。
30 | for( GrantedAuthority grantedAuthority: authentication.getAuthorities()){
31 | if(needRole.trim().equals(grantedAuthority.getAuthority().trim())){
32 | return;
33 | }
34 | }
35 | }
36 | /**
37 | * 如果一个AccessDeniedException被抛出并且用户已经被认证,那么这意味着一个操作已经尝试了它们不具有足够的权限。
38 | * 在这种情况下,ExceptionTranslationFilter将调用第二策略,AccessDeniedHandler。
39 | * 默认情况下,AccessDeniedHandlerImpl被使用,这只是发送一个403(禁止)响应于客户端。
40 | * 此外,还可以配置明确的实例,并设置一个错误页面的URL,它会请求转发 .
41 | * 这可以是一个简单的“拒绝访问”页上,如一个JSP,或者它可以是更复杂的处理程序,如一个MVC的控制器。
42 | * 当然,你可以自己实现接口,并使用自己的实现。
43 | */
44 | throw new AccessDeniedException("权限不足");
45 | }
46 |
47 | @Override
48 | public boolean supports(ConfigAttribute attribute) {
49 | return true;
50 | }
51 |
52 | @Override
53 | public boolean supports(Class> clazz) {
54 | return true;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/config/security/CSRFSecurityRequestMatcher.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config.security;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.security.web.util.matcher.RequestMatcher;
5 |
6 | import javax.servlet.http.HttpServletRequest;
7 | import java.util.Arrays;
8 | import java.util.HashSet;
9 | import java.util.Set;
10 |
11 | /**
12 | * 自定义CSRF匹配,排除不需要CSRF防御的资源,比如给第三方开放的接口
13 | * 默认使用的是DefaultRequiresCsrfMatcher
14 | */
15 | @Slf4j
16 | public class CSRFSecurityRequestMatcher implements RequestMatcher {
17 |
18 | private final HashSet allowedMethods = new HashSet(
19 | Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));
20 | //需要排除URL
21 | private Set excludedUrls ;
22 |
23 | @Override
24 | public boolean matches(HttpServletRequest request) {
25 | if (excludedUrls!=null && excludedUrls.size()>0){
26 | String seveletPath = request.getServletPath();
27 | for (String excludedUrl : excludedUrls) {
28 | if (seveletPath.contains(excludedUrl)){
29 | return false;
30 | }
31 | }
32 | }
33 | return !this.allowedMethods.contains(request.getMethod());
34 | }
35 |
36 | public Set getExcludedUrls() {
37 | return excludedUrls;
38 | }
39 |
40 | public void setExcludedUrls(Set excludedUrls) {
41 | this.excludedUrls = excludedUrls;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/config/security/FilterInvocationSecurityMetadataSourceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config.security;
2 |
3 | import cn.geekview.domain.entity.Resource;
4 | import cn.geekview.domain.entity.Role;
5 | import cn.geekview.domain.repository.ResourceRepository;
6 | import cn.geekview.domain.repository.RoleRepository;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.security.access.ConfigAttribute;
9 | import org.springframework.security.access.SecurityConfig;
10 | import org.springframework.security.web.FilterInvocation;
11 | import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
12 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
13 | import org.springframework.security.web.util.matcher.RequestMatcher;
14 | import org.springframework.stereotype.Component;
15 |
16 | import javax.annotation.PostConstruct;
17 | import java.util.*;
18 |
19 | /**
20 | * 处理资源与角色之间的关系:系统在启动的时候就要加载资源与角色的数据
21 | */
22 | @Component
23 | public class FilterInvocationSecurityMetadataSourceImpl implements FilterInvocationSecurityMetadataSource {
24 |
25 | @Autowired
26 | private RoleRepository roleRepository;
27 |
28 | @Autowired
29 | private ResourceRepository resourceRepository;
30 |
31 | private static Map> resourceMap = null;
32 |
33 | @PostConstruct
34 | private void loadResourceDefine() {
35 | // 在Web服务器启动时,提取系统中的所有权限。
36 | List roleList =roleRepository.findAll();
37 |
38 | List roleNameList = new ArrayList();
39 | if(roleList!=null && roleList.size()>0) {
40 | for (Role role : roleList) {
41 | roleNameList.add(role.getRoleName());
42 | }
43 | }
44 | /*
45 | * 应当是资源为key, 权限为value。 资源通常为url, 权限就是那些以ROLE_为前缀的角色。
46 | * 一个资源可以由多个权限来访问。
47 | *
48 | */
49 | resourceMap = new HashMap>();
50 | for (String roleName : roleNameList) {
51 | // 将角色名封装一个安全配置???这样理解有点不准确, 说白了就是一个角色名,只是为了和框架整合换一种说法
52 | ConfigAttribute configAttribute = new SecurityConfig(roleName);
53 | List urlList = new ArrayList();
54 | List resourceList = resourceRepository.findByRoleName(roleName);
55 | if(resourceList!=null && resourceList.size()>0) {//如果不加判断,这里如果 resourceRepository.findByRoleName(roleName);为null.则会报错
56 | for(Resource resource :resourceList){
57 | urlList.add(resource.getResource());
58 | }
59 | }
60 | for (String res : urlList) {
61 | String url = res;
62 | /*
63 | * 判断资源文件和权限的对应关系,如果已经存在相关的资源url,
64 | * 则要通过该url为key提取出权限集合,将权限增加到权限集合中。
65 | *
66 | */
67 | if (resourceMap.containsKey(url)) {
68 | Collection value = resourceMap.get(url);
69 | value.add(configAttribute);
70 | resourceMap.put(url, value);
71 | } else {
72 | Collection atts = new ArrayList();
73 | atts.add(configAttribute);
74 | resourceMap.put(url, atts);// 一个URL对应多种角色
75 | }
76 | }
77 | }
78 |
79 | }
80 |
81 | @Override
82 | public Collection getAttributes(Object object) throws IllegalArgumentException {
83 | // object 是一个URL,被用户请求的url。
84 | FilterInvocation filterInvocation = (FilterInvocation) object;
85 | if (resourceMap == null) {
86 | loadResourceDefine();
87 | }
88 | Iterator iterator = resourceMap.keySet().iterator();
89 | while (iterator.hasNext()) {
90 | String resURL = iterator.next();
91 | // 优化请求路径后面带参数的部分
92 | RequestMatcher requestMatcher = new AntPathRequestMatcher(resURL);
93 | if(requestMatcher.matches(filterInvocation.getHttpRequest())) {
94 | return resourceMap.get(resURL);
95 | }
96 | }
97 | return null;
98 | }
99 |
100 | @Override
101 | public Collection getAllConfigAttributes() {
102 | // 根据DefaultFilterInvocationSecurityMetadataSource写的
103 | Set allAttributes = new HashSet();
104 | for (Map.Entry> entry : resourceMap.entrySet()) {
105 | allAttributes.addAll(entry.getValue());
106 | }
107 | return allAttributes;
108 | }
109 |
110 | @Override
111 | public boolean supports(Class> clazz) {
112 | return true;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/config/security/WebSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.config.security;
2 |
3 | import cn.geekview.handler.LoginFailureHandler;
4 | import cn.geekview.handler.LoginSuccessHandler;
5 | import cn.geekview.service.IUserService;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.security.authentication.AuthenticationManager;
10 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
11 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
12 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
13 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
14 | import org.springframework.security.core.AuthenticationException;
15 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
16 | import org.springframework.security.crypto.password.PasswordEncoder;
17 | import org.springframework.security.web.AuthenticationEntryPoint;
18 | import org.springframework.security.web.WebAttributes;
19 | import org.springframework.security.web.access.AccessDeniedHandlerImpl;
20 | import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
21 | import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
22 | import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
23 | import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
24 | import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
25 | import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
26 | import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
27 |
28 | import javax.servlet.RequestDispatcher;
29 | import javax.servlet.ServletException;
30 | import javax.servlet.http.HttpServletRequest;
31 | import javax.servlet.http.HttpServletResponse;
32 | import javax.sql.DataSource;
33 | import java.io.IOException;
34 | import java.util.HashSet;
35 | import java.util.Set;
36 |
37 | @Configuration
38 | @EnableWebSecurity
39 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
40 |
41 | @Autowired
42 | private IUserService userService;
43 |
44 | @Override
45 | protected void configure(AuthenticationManagerBuilder auth) throws Exception {
46 | auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
47 | }
48 |
49 | @Override
50 | protected void configure(HttpSecurity http) throws Exception {
51 | http
52 | // .addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class)//在正确的位置添加我们自定义的过滤器
53 | // 重新添加拥有自己属性的过滤器;
54 | /**
55 | * 不使用自定义过滤器类的话,可以直接使用默认实现的类,并提供自定义的属性
56 | */
57 | .addFilter(filterSecurityInterceptor())
58 | .authorizeRequests()
59 | //路径/home不需要验证
60 | .antMatchers("/home").permitAll()
61 | //任何请求都需要授权
62 | .anyRequest().authenticated()
63 | .and()
64 | .formLogin()
65 | .loginPage("/login")//之所以加true 是因为 th:if{param.error} 会去读取浏览器地址携带的参数,有了true之后,if就成立,所以后面的th:text就能执行。
66 | .permitAll()
67 | //登录失败处理
68 | .failureHandler(loginFailureHandler())
69 | //登录成功处理
70 | .successHandler(loginSuccessHandler())
71 | .and()
72 | .logout()
73 | .permitAll()
74 | //注销后使session相关信息无效
75 | .invalidateHttpSession(true)
76 | .and()
77 | // 开启rememberme功能:验证,登录成功后,关闭页面,直接访问登陆后可以访问的页面
78 | .rememberMe()
79 | //持久化到数据库 如果不需要持久化到数据库,直接注释掉即可
80 | .rememberMeServices(new PersistentTokenBasedRememberMeServices("MySpringSecurityCookie",userService,persistentTokenRepository()))
81 | //设置有效时间
82 | .tokenValiditySeconds(7*24*60*60)
83 | .and()
84 | .csrf()
85 | //自定义匹配器,方便排除那些不需要csrf防御的地址
86 | .requireCsrfProtectionMatcher(csrfSecurityRequestMatcher())
87 | .csrfTokenRepository(new HttpSessionCsrfTokenRepository());
88 | /**
89 | * 处理AccessDeniedException 且用户不是匿名用户
90 | * 例如:USER角色访问ADMIN角色的资源,提示权限不足
91 | */
92 | http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandlerImpl()).accessDeniedPage("/deny");
93 | /**
94 | * 1、处理AuthenticationException
95 | * 2、处理AccessDeniedException 且用户是匿名用户
96 | * 例如:用户注册之后没有激活提示DisabledException
97 | */
98 | http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint());
99 | }
100 |
101 | @Bean
102 | public AuthenticationEntryPoint authenticationEntryPoint(){
103 | return new AuthenticationEntryPoint() {
104 | String errorPage = "/deny";
105 | @Override
106 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
107 | System.out.println(authException.getMessage());
108 | if (!response.isCommitted()) {
109 | if (errorPage != null) {
110 | // Put exception into request scope (perhaps of use to a view)
111 | request.setAttribute(WebAttributes.ACCESS_DENIED_403,
112 | authException);
113 |
114 | // Set the 403 status code.
115 | response.setStatus(HttpServletResponse.SC_FORBIDDEN);
116 |
117 | // forward to error page.
118 | RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage);
119 | dispatcher.forward(request, response);
120 | }
121 | else {
122 | response.sendError(HttpServletResponse.SC_FORBIDDEN,
123 | authException.getMessage());
124 | }
125 | }
126 | }
127 | };
128 | }
129 |
130 | @Autowired
131 | private DataSource dataSource;
132 |
133 | @Bean
134 | public PersistentTokenRepository persistentTokenRepository(){
135 | JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
136 | // 设置数据源 默认使用的Apache的连接池
137 | jdbcTokenRepository.setDataSource(dataSource);
138 | // 设置初始化存储Token的表 方便调试 由于源码没有对数据库中是否有表结构做出判断,正常使用的时候不建议开启,不然第二次启动会报错!
139 | // jdbcTokenRepository.setCreateTableOnStartup(true);
140 | return jdbcTokenRepository;
141 | }
142 |
143 | @Bean
144 | public PasswordEncoder passwordEncoder(){
145 | return new BCryptPasswordEncoder();
146 | }
147 |
148 | @Bean
149 | public LoginSuccessHandler loginSuccessHandler(){
150 | return new LoginSuccessHandler();
151 | }
152 |
153 | @Bean
154 | public LoginFailureHandler loginFailureHandler(){
155 | return new LoginFailureHandler();
156 | }
157 |
158 | @Autowired
159 | private FilterInvocationSecurityMetadataSourceImpl securityMetadataSource;
160 |
161 | @Autowired
162 | private AccessDecisionManagerImpl accessDecisionManager;
163 |
164 | @Autowired
165 | private AuthenticationManager authenticationManager;
166 |
167 | @Bean
168 | public FilterSecurityInterceptor filterSecurityInterceptor(){
169 | FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
170 | filterSecurityInterceptor.setSecurityMetadataSource(securityMetadataSource);
171 | filterSecurityInterceptor.setAccessDecisionManager(accessDecisionManager);
172 | filterSecurityInterceptor.setAuthenticationManager(authenticationManager);
173 | return filterSecurityInterceptor;
174 | }
175 |
176 | @Bean
177 | public CSRFSecurityRequestMatcher csrfSecurityRequestMatcher(){
178 | Set excludedUrls = new HashSet<>();
179 | excludedUrls.add("/vip/");
180 | CSRFSecurityRequestMatcher csrfSecurityRequestMatcher = new CSRFSecurityRequestMatcher();
181 | csrfSecurityRequestMatcher.setExcludedUrls(excludedUrls);
182 | return csrfSecurityRequestMatcher;
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/controller/IndexController.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.controller;
2 |
3 | import org.springframework.stereotype.Controller;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.PostMapping;
6 | import org.springframework.web.bind.annotation.RequestMapping;
7 |
8 | @Controller
9 | public class IndexController {
10 |
11 | @RequestMapping(value = {"/","/home"})
12 | public String home(){
13 | return "home";
14 | }
15 |
16 | @RequestMapping(value = {"/admin"})
17 | public String admin(){
18 | return "admin";
19 | }
20 |
21 | @RequestMapping(value = {"/user"})
22 | public String user(){
23 | return "user";
24 | }
25 |
26 | @RequestMapping(value = {"/vip"})
27 | public String vip(){
28 | return "vip";
29 | }
30 |
31 | @RequestMapping(value = {"/super"})
32 | public String superm(){
33 | return "super";
34 | }
35 |
36 | @RequestMapping(value = {"/deny"})
37 | public String deny(){
38 | return "deny";
39 | }
40 |
41 | @GetMapping("/regist")
42 | public String regist(){
43 | return "regist";
44 | }
45 |
46 | @GetMapping("/login")
47 | public String login(){
48 | return "login";
49 | }
50 |
51 | @GetMapping("/CSRFTest")
52 | public String product(){
53 | return "CSRFTest";
54 | }
55 |
56 | @PostMapping("/CSRFTestcheck")
57 | public String product1(){
58 | return "home";
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.controller;
2 |
3 | import cn.geekview.domain.dto.RegistraFormDTO;
4 | import cn.geekview.domain.entity.User;
5 | import cn.geekview.domain.entity.ValidateToken;
6 | import cn.geekview.event.OnRegistrationCompleteEvent;
7 | import cn.geekview.service.IUserService;
8 | import cn.geekview.util.ValidateCode;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.joda.time.DateTime;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.context.ApplicationEventPublisher;
13 | import org.springframework.security.crypto.password.PasswordEncoder;
14 | import org.springframework.stereotype.Controller;
15 | import org.springframework.ui.Model;
16 | import org.springframework.validation.BindingResult;
17 | import org.springframework.web.bind.annotation.GetMapping;
18 | import org.springframework.web.bind.annotation.PostMapping;
19 | import org.springframework.web.bind.annotation.RequestMapping;
20 | import org.springframework.web.context.request.WebRequest;
21 | import org.springframework.web.servlet.ModelAndView;
22 |
23 | import javax.servlet.http.HttpServletRequest;
24 | import javax.servlet.http.HttpServletResponse;
25 | import javax.servlet.http.HttpSession;
26 | import javax.transaction.Transactional;
27 | import javax.validation.Valid;
28 |
29 | @Controller
30 | @Slf4j
31 | public class UserController {
32 |
33 | @Autowired
34 | private IUserService userService;
35 |
36 | @Autowired
37 | private PasswordEncoder passwordEncoder;
38 |
39 | @Autowired
40 | private ApplicationEventPublisher eventPublisher;
41 |
42 | // 注册
43 | @PostMapping("/registra")
44 | public ModelAndView registra(@Valid RegistraFormDTO registraFormDTO, BindingResult result, WebRequest request){
45 | // 校验表单字段
46 | if (result.hasErrors()){
47 | return new ModelAndView("regist","message",result.getFieldError());
48 | }
49 | // 保存注册信息
50 | User user = new User();
51 | user.setUsername(registraFormDTO.getUsername());
52 | user.setPassword(passwordEncoder.encode(registraFormDTO.getPassword()));
53 | user.setEmail(registraFormDTO.getEmail());
54 | User registrated = userService.creatNewUser(user);
55 | // 发布邮箱验证事件
56 | String appUrl = request.getContextPath();
57 | if (registrated == null){
58 | return new ModelAndView("regist","message","该邮箱已经注册!!!");
59 | }
60 | try {
61 | eventPublisher.publishEvent(new OnRegistrationCompleteEvent(user,appUrl));
62 | }catch (Exception e){
63 | log.debug(e.getMessage());
64 | return new ModelAndView("regist","message","请确认邮箱状态是否正常!!!");
65 | }
66 | return new ModelAndView("redirect:/login");
67 | }
68 | /**
69 | * 邮箱验证
70 | * 1、判断token是否存在
71 | * 2、判断是否过期
72 | */
73 | @GetMapping("/registationConfirm")
74 | public String registationConfirm(String token, Model model){
75 | ValidateToken validateToken = userService.findValidateToken(token);
76 | if (validateToken == null) {
77 | model.addAttribute("message","请求地址中的Token不存在");
78 | return "redirect:/regist";
79 | }
80 | if (validateToken.getExpiryDate().getTime()- DateTime.now().getMillis()<0){
81 | model.addAttribute("message","请求地址中的Token已过期");
82 | return "redirect:/regist";
83 | }
84 | User user = validateToken.getUser();
85 | user.setEnabled(true);
86 | userService.saveRegistratedUser(user);
87 | return "redirect:/login";
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/domain/dto/RegistraFormDTO.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.domain.dto;
2 |
3 | import lombok.Data;
4 | import javax.validation.constraints.NotNull;
5 | import org.hibernate.validator.constraints.Email;
6 | import org.hibernate.validator.constraints.NotEmpty;
7 |
8 | import javax.validation.constraints.Size;
9 |
10 | /**
11 | * 注册表单数据传输对象
12 | */
13 | @Data
14 | public class RegistraFormDTO {
15 |
16 | @NotEmpty
17 | @NotNull
18 | @Size(max = 255)
19 | private String username;
20 |
21 | @NotEmpty
22 | @NotNull
23 | @Size(min = 6,max = 32)
24 | private String password;
25 |
26 | @NotEmpty
27 | @NotNull
28 | @Email
29 | private String email;
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/domain/entity/Resource.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.domain.entity;
2 |
3 | import lombok.Data;
4 |
5 | import javax.persistence.*;
6 | import java.util.HashMap;
7 | import java.util.HashSet;
8 | import java.util.Set;
9 |
10 | @Data
11 | @Entity
12 | @Table(name = "t_resource")
13 | public class Resource {
14 |
15 | @Id
16 | @GeneratedValue(strategy = GenerationType.AUTO)
17 | private Long id;
18 |
19 | private String resource;
20 |
21 | @ManyToMany(fetch = FetchType.LAZY,
22 | cascade = {
23 | CascadeType.PERSIST,
24 | CascadeType.MERGE
25 | },
26 | mappedBy = "resources")
27 | private Set roles = new HashSet<>();
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/domain/entity/Role.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.domain.entity;
2 |
3 | import lombok.Data;
4 |
5 | import javax.persistence.*;
6 | import java.util.HashSet;
7 | import java.util.Set;
8 |
9 | @Data
10 | @Entity
11 | @Table(name = "t_role")
12 | public class Role {
13 |
14 | @Id
15 | @GeneratedValue(strategy = GenerationType.AUTO)
16 | private Long id;
17 |
18 | private String roleName;
19 |
20 | @ManyToMany(targetEntity = User.class,mappedBy = "roles",fetch = FetchType.EAGER)
21 | private Set users = new HashSet<>();
22 |
23 | @ManyToMany(fetch = FetchType.EAGER,
24 | cascade = {
25 | CascadeType.PERSIST,
26 | CascadeType.MERGE
27 | })
28 | @JoinTable(name = "t_role_resorces",
29 | joinColumns = { @JoinColumn(name = "roles_id") },
30 | inverseJoinColumns = { @JoinColumn(name = "resources_id") })
31 | private Set resources = new HashSet<>();
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/domain/entity/User.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.domain.entity;
2 |
3 | import org.springframework.security.core.GrantedAuthority;
4 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
5 | import org.springframework.security.core.userdetails.UserDetails;
6 |
7 | import javax.persistence.*;
8 | import java.util.ArrayList;
9 | import java.util.Collection;
10 | import java.util.HashSet;
11 | import java.util.Set;
12 |
13 | /**
14 | * 这里不能使用lombok @Data注解
15 | * 否则会出现@ManyToMany死循环导致内存溢出
16 | * 否则就是org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cn.geekview.domain.entity.User.roles, could not initialize proxy - no Session
17 | *
18 | * ???
19 | *
20 | */
21 | @Entity
22 | @Table(name = "t_user")
23 | public class User implements UserDetails{
24 |
25 | @Id
26 | @GeneratedValue(strategy = GenerationType.AUTO)
27 | private Long id;
28 |
29 | private String username;
30 |
31 | private String password;
32 |
33 | private String email;
34 |
35 | /*
36 | AbstractUserDetailsAuthenticationProvider的私有内部类DefaultPreAuthenticationChecks会对用户是否可用进行校验
37 | */
38 | private boolean enabled;
39 |
40 | public User(){
41 | this.enabled = false;
42 | }
43 |
44 | /**
45 | * CascadeType.DETACH
46 | Cascade detach operation,级联脱管/游离操作。
47 | 如果你要删除一个实体,但是它有外键无法删除,你就需要这个级联权限了。它会撤销所有相关的外键关联。
48 | */
49 | @ManyToMany(targetEntity = Role.class,fetch = FetchType.EAGER)
50 | private Set roles = new HashSet<>();
51 |
52 |
53 | @Override
54 | public Collection extends GrantedAuthority> getAuthorities() {
55 | Collection grantedAuthorities = new ArrayList<>();
56 | for (Role role : roles) {
57 | SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(role.getRoleName());
58 | grantedAuthorities.add(simpleGrantedAuthority);
59 | }
60 | return grantedAuthorities;
61 | }
62 |
63 | @Override
64 | public boolean isAccountNonExpired() {
65 | return true;
66 | }
67 |
68 | @Override
69 | public boolean isAccountNonLocked() {
70 | return true;
71 | }
72 |
73 | @Override
74 | public boolean isCredentialsNonExpired() {
75 | return true;
76 | }
77 |
78 | public Long getId() {
79 | return id;
80 | }
81 |
82 | public void setId(Long id) {
83 | this.id = id;
84 | }
85 |
86 | @Override
87 | public String getUsername() {
88 | return username;
89 | }
90 |
91 | public void setUsername(String username) {
92 | this.username = username;
93 | }
94 |
95 | @Override
96 | public String getPassword() {
97 | return password;
98 | }
99 |
100 | public void setPassword(String password) {
101 | this.password = password;
102 | }
103 |
104 | public String getEmail() {
105 | return email;
106 | }
107 |
108 | public void setEmail(String email) {
109 | this.email = email;
110 | }
111 |
112 | public Set getRoles() {
113 | return roles;
114 | }
115 |
116 | public void setRoles(Set roles) {
117 | this.roles = roles;
118 | }
119 |
120 | @Override
121 | public boolean isEnabled() {
122 | return enabled;
123 | }
124 |
125 | public void setEnabled(boolean enabled) {
126 | this.enabled = enabled;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/domain/entity/ValidateToken.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.domain.entity;
2 |
3 | import lombok.Data;
4 | import org.joda.time.DateTime;
5 |
6 | import javax.persistence.*;
7 | import java.util.Date;
8 |
9 | /**
10 | * 与注册用户一一对应
11 | */
12 | @Data
13 | @Entity
14 | @Table(name = "t_validatetoken")
15 | public class ValidateToken {
16 |
17 | private final static int EXPIRY = 24*60;
18 |
19 | @Id
20 | @GeneratedValue(strategy = GenerationType.AUTO)
21 | private Long id;
22 |
23 | /**
24 | * @OneToOne 注释只能确定实体与实体的关系是一对一的关系,
25 | * 不能指定数据库表中的保存的关联字段。
26 | * 所以此时要结合@JoinColumn标记来指定保存实体关系的配置。
27 | */
28 | @OneToOne(targetEntity = User.class,fetch = FetchType.EAGER)
29 | @JoinColumn(nullable = false,name = "user_id")
30 | private User user;
31 |
32 | private String token;
33 |
34 | private Date expiryDate;
35 |
36 | public ValidateToken(User user,String token){
37 | this.user = user;
38 | this.token = token;
39 | this.expiryDate = DateTime.now().plusMinutes(EXPIRY).toDate();
40 | }
41 |
42 | public ValidateToken(){
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/domain/repository/ResourceRepository.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.domain.repository;
2 |
3 | import cn.geekview.domain.entity.Resource;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.data.jpa.repository.Query;
6 |
7 | import java.util.List;
8 |
9 | public interface ResourceRepository extends JpaRepository {
10 |
11 | @Query(value = "SELECT * FROM t_resource WHERE id IN ( SELECT resources_id FROM t_role_resources WHERE roles_id = ( SELECT id FROM t_role WHERE role_name = ?1))",nativeQuery = true)
12 | List findByRoleName(String rolename);
13 | }
14 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/domain/repository/RoleRepository.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.domain.repository;
2 |
3 | import cn.geekview.domain.entity.Role;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface RoleRepository extends JpaRepository{
7 | }
8 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/domain/repository/UserRepository.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.domain.repository;
2 |
3 | import cn.geekview.domain.entity.User;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface UserRepository extends JpaRepository {
7 |
8 | User findByUsername(String username);
9 |
10 | User findByEmail(String eamil);
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/domain/repository/ValidateTokenRepository.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.domain.repository;
2 |
3 | import cn.geekview.domain.entity.ValidateToken;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface ValidateTokenRepository extends JpaRepository {
7 |
8 | ValidateToken findByToken(String token);
9 | }
10 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/event/OnRegistrationCompleteEvent.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.event;
2 |
3 | import cn.geekview.domain.entity.User;
4 | import org.springframework.context.ApplicationEvent;
5 |
6 |
7 | public class OnRegistrationCompleteEvent extends ApplicationEvent {
8 |
9 | private final String appUrl;
10 |
11 | private final User user;
12 |
13 |
14 | public OnRegistrationCompleteEvent(final User user, final String appUrl) {
15 | super(user);
16 | this.user = user;
17 | this.appUrl = appUrl;
18 | }
19 |
20 | public String getAppUrl() {
21 | return appUrl;
22 | }
23 |
24 |
25 | public User getUser() {
26 | return user;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/event/listener/RegistrationListener.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.event.listener;
2 |
3 | import cn.geekview.domain.entity.User;
4 | import cn.geekview.domain.entity.ValidateToken;
5 | import cn.geekview.event.OnRegistrationCompleteEvent;
6 | import cn.geekview.service.IUserService;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.context.ApplicationListener;
9 | import org.springframework.core.env.Environment;
10 | import org.springframework.mail.SimpleMailMessage;
11 | import org.springframework.mail.javamail.JavaMailSender;
12 | import org.springframework.stereotype.Component;
13 |
14 | import java.util.UUID;
15 |
16 | /**
17 | * 1、生成并保存邮箱验证令牌
18 | * 2、发送验证邮件
19 | */
20 | @Component
21 | public class RegistrationListener implements ApplicationListener {
22 |
23 | @Autowired
24 | private JavaMailSender mailSender;
25 |
26 | @Autowired
27 | private IUserService userService;
28 |
29 | @Autowired
30 | private Environment environment;
31 |
32 | @Override
33 | public void onApplicationEvent(OnRegistrationCompleteEvent event) {
34 | User user = event.getUser();
35 | String appurl = event.getAppUrl();
36 | String token = UUID.randomUUID().toString();
37 | ValidateToken validateToken = new ValidateToken(user,token);
38 | userService.saveValidateToken(validateToken);
39 |
40 | SimpleMailMessage mailMessage = new SimpleMailMessage();
41 | mailMessage.setSubject("注册确认邮件");
42 | mailMessage.setText("http://localhost:80"+appurl+"/registationConfirm?token="+token);
43 | mailMessage.setTo(user.getEmail());
44 | mailMessage.setFrom(environment.getProperty("mail.from.addr"));
45 |
46 | mailSender.send(mailMessage);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/handler/LoginFailureHandler.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.handler;
2 |
3 | import org.springframework.security.core.AuthenticationException;
4 | import org.springframework.security.web.DefaultRedirectStrategy;
5 | import org.springframework.security.web.RedirectStrategy;
6 | import org.springframework.security.web.WebAttributes;
7 | import org.springframework.security.web.authentication.AuthenticationFailureHandler;
8 |
9 | import javax.servlet.ServletException;
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 | import java.io.IOException;
13 |
14 | public class LoginFailureHandler implements AuthenticationFailureHandler{
15 |
16 | private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
17 |
18 | @Override
19 | public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
20 | System.out.println("++++++++++++++>"+exception);
21 | if ("User is disabled".equals(exception.getMessage())){
22 | request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, "用户没有激活,请激活!");
23 | }else {
24 | request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
25 | }
26 | redirectStrategy.sendRedirect(request,response,"/login");
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/handler/LoginSuccessHandler.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.handler;
2 |
3 | import cn.geekview.domain.entity.User;
4 | import cn.geekview.domain.repository.ResourceRepository;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.security.core.Authentication;
7 | import org.springframework.security.core.GrantedAuthority;
8 | import org.springframework.security.web.DefaultRedirectStrategy;
9 | import org.springframework.security.web.RedirectStrategy;
10 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
11 | import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
12 |
13 | import javax.servlet.ServletException;
14 | import javax.servlet.http.HttpServletRequest;
15 | import javax.servlet.http.HttpServletResponse;
16 | import java.io.IOException;
17 |
18 | /**
19 | * 登录成功处理器
20 | * 需求:
21 | * 登录成功后,默认跳转到对应角色下的页面
22 | */
23 | public class LoginSuccessHandler implements AuthenticationSuccessHandler {
24 |
25 | private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
26 |
27 | @Override
28 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException,
29 | ServletException {
30 | System.out.println(authentication);
31 |
32 | System.out.println(authentication.getPrincipal());//用户对象
33 | //获得授权后可得到用户信息
34 | User user = (User) authentication.getPrincipal();
35 |
36 | //输出登录提示信息
37 | System.out.println("用户名: " + user.getUsername());
38 |
39 | System.out.println("用户密码: " + authentication.getCredentials());
40 |
41 | System.out.println("角色列表:"+authentication.getAuthorities());
42 |
43 | System.out.println("IP信息 :"+authentication.getDetails());
44 |
45 | System.out.println("是否被授权 :"+authentication.isAuthenticated());
46 |
47 | //登录成功后跳转到默认对应的页面
48 | String targetUrl = "/home";
49 | for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
50 | String roleName = grantedAuthority.getAuthority();
51 | switch (roleName){
52 | case "SUPER": targetUrl = "/super";break;
53 | case "ADMIN": targetUrl = "/admin";break;
54 | case "VIP": targetUrl = "/vip";break;
55 | case "USER": targetUrl = "/user";break;
56 | }
57 | }
58 | redirectStrategy.sendRedirect(request,response,targetUrl);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/service/IUserService.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.service;
2 |
3 | import cn.geekview.domain.entity.User;
4 | import cn.geekview.domain.entity.ValidateToken;
5 | import org.springframework.security.core.userdetails.UserDetailsService;
6 |
7 | public interface IUserService extends UserDetailsService{
8 |
9 | User creatNewUser(User user);
10 |
11 | void saveValidateToken(ValidateToken token);
12 |
13 | ValidateToken findValidateToken(String token);
14 |
15 | void saveRegistratedUser(User user);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/service/impl/UserServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.service.impl;
2 |
3 | import cn.geekview.domain.entity.User;
4 | import cn.geekview.domain.entity.ValidateToken;
5 | import cn.geekview.domain.repository.UserRepository;
6 | import cn.geekview.domain.repository.ValidateTokenRepository;
7 | import cn.geekview.service.IUserService;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.security.authentication.DisabledException;
11 | import org.springframework.security.core.userdetails.UserDetails;
12 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
13 | import org.springframework.stereotype.Service;
14 |
15 | import javax.transaction.Transactional;
16 |
17 | @Service
18 | @Slf4j
19 | @Transactional
20 | public class UserServiceImpl implements IUserService {
21 |
22 | @Autowired
23 | private UserRepository userRepository;
24 |
25 | @Autowired
26 | private ValidateTokenRepository tokenRepository;
27 |
28 | /**
29 | * 邮箱登录,邮箱地址替换用户名称
30 | * @param email
31 | * @return
32 | * @throws UsernameNotFoundException
33 | */
34 | @Override
35 | public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
36 | User user = userRepository.findByEmail(email);
37 | if (user == null) {
38 | throw new UsernameNotFoundException("用户名不存在");
39 | }
40 | return user;
41 |
42 | }
43 |
44 | /**
45 | * 创建一个新的账户
46 | * @param user
47 | * @return
48 | */
49 | @Override
50 | public User creatNewUser(User user) {
51 | if (isEmailExist(user.getEmail())){
52 | return null;
53 | }else {
54 | return userRepository.save(user);
55 | }
56 | }
57 |
58 | /**
59 | * 保存验证令牌
60 | * @param validateToken
61 | */
62 | @Override
63 | public void saveValidateToken(ValidateToken validateToken) {
64 | tokenRepository.save(validateToken);
65 | }
66 |
67 | @Override
68 | public ValidateToken findValidateToken(String token) {
69 | return tokenRepository.findByToken(token);
70 | }
71 |
72 | @Override
73 | public void saveRegistratedUser(User user) {
74 | userRepository.save(user);
75 | }
76 |
77 | /**
78 | * 判断邮箱是否已经存在
79 | * @param email
80 | * @return
81 | */
82 | public boolean isEmailExist(String email){
83 | User user = userRepository.findByEmail(email);
84 | if (user==null){
85 | return false;
86 | }else {
87 | return true;
88 | }
89 | }
90 |
91 |
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/java/cn/geekview/util/ValidateCode.java:
--------------------------------------------------------------------------------
1 | package cn.geekview.util;
2 |
3 | import javax.imageio.ImageIO;
4 | import java.awt.*;
5 | import java.awt.image.BufferedImage;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.io.OutputStream;
9 | import java.util.Date;
10 | import java.util.Random;
11 |
12 | /**
13 | * 验证码生成器
14 | *
15 | * @author
16 | */
17 | public class ValidateCode {
18 | // 图片的宽度。
19 | private int width = 160;
20 | // 图片的高度。
21 | private int height = 40;
22 | // 验证码字符个数
23 | private int codeCount = 5;
24 | // 验证码干扰线数
25 | private int lineCount = 150;
26 | // 验证码
27 | private String code = null;
28 | // 验证码图片Buffer
29 | private BufferedImage buffImg = null;
30 |
31 | // 验证码范围,去掉0(数字)和O(拼音)容易混淆的(小写的1和L也可以去掉,大写不用了)
32 | private char[] codeSequence = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
33 | 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
34 | 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
35 |
36 | /**
37 | * 默认构造函数,设置默认参数
38 | */
39 | public ValidateCode() {
40 | this.createCode();
41 | }
42 |
43 | /**
44 | * @param width 图片宽
45 | * @param height 图片高
46 | */
47 | public ValidateCode(int width, int height) {
48 | this.width = width;
49 | this.height = height;
50 | this.createCode();
51 | }
52 |
53 | /**
54 | * @param width 图片宽
55 | * @param height 图片高
56 | * @param codeCount 字符个数
57 | * @param lineCount 干扰线条数
58 | */
59 | public ValidateCode(int width, int height, int codeCount, int lineCount) {
60 | this.width = width;
61 | this.height = height;
62 | this.codeCount = codeCount;
63 | this.lineCount = lineCount;
64 | this.createCode();
65 | }
66 |
67 | public void createCode() {
68 | int x = 0, fontHeight = 0, codeY = 0;
69 | int red = 0, green = 0, blue = 0;
70 |
71 | x = width / (codeCount + 2);//每个字符的宽度(左右各空出一个字符)
72 | fontHeight = height - 2;//字体的高度
73 | codeY = height - 4;
74 |
75 | // 图像buffer
76 | buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
77 | Graphics2D g = buffImg.createGraphics();
78 | // 生成随机数
79 | Random random = new Random();
80 | // 将图像填充为白色
81 | g.setColor(Color.WHITE);
82 | g.fillRect(0, 0, width, height);
83 | // 创建字体,可以修改为其它的
84 | Font font = new Font("Fixedsys", Font.PLAIN, fontHeight);
85 | // Font font = new Font("Times New Roman", Font.ROMAN_BASELINE, fontHeight);
86 | g.setFont(font);
87 |
88 | for (int i = 0; i < lineCount; i++) {
89 | // 设置随机开始和结束坐标
90 | int xs = random.nextInt(width);//x坐标开始
91 | int ys = random.nextInt(height);//y坐标开始
92 | int xe = xs + random.nextInt(width / 8);//x坐标结束
93 | int ye = ys + random.nextInt(height / 8);//y坐标结束
94 |
95 | // 产生随机的颜色值,让输出的每个干扰线的颜色值都将不同。
96 | red = random.nextInt(255);
97 | green = random.nextInt(255);
98 | blue = random.nextInt(255);
99 | g.setColor(new Color(red, green, blue));
100 | g.drawLine(xs, ys, xe, ye);
101 | }
102 |
103 | // randomCode记录随机产生的验证码
104 | StringBuffer randomCode = new StringBuffer();
105 | // 随机产生codeCount个字符的验证码。
106 | for (int i = 0; i < codeCount; i++) {
107 | String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
108 | // 产生随机的颜色值,让输出的每个字符的颜色值都将不同。
109 | red = random.nextInt(255);
110 | green = random.nextInt(255);
111 | blue = random.nextInt(255);
112 | g.setColor(new Color(red, green, blue));
113 | g.drawString(strRand, (i + 1) * x, codeY);
114 | // 将产生的四个随机数组合在一起。
115 | randomCode.append(strRand);
116 | }
117 | // 将四位数字的验证码保存到Session中。
118 | code = randomCode.toString();
119 | }
120 |
121 | public void write(String path) throws IOException {
122 | OutputStream sos = new FileOutputStream(path);
123 | this.write(sos);
124 | }
125 |
126 | public void write(OutputStream sos) throws IOException {
127 | ImageIO.write(buffImg, "png", sos);
128 | sos.close();
129 | }
130 |
131 | public BufferedImage getBuffImg() {
132 | return buffImg;
133 | }
134 |
135 | public String getCode() {
136 | return code;
137 | }
138 |
139 | /**
140 | * 测试函数,默认生成到d盘
141 | * @param args
142 | */
143 | public static void main(String[] args) {
144 | ValidateCode vCode = new ValidateCode(160,40,5,150);
145 | try {
146 | String path="C:/"+new Date().getTime()+".png";
147 | System.out.println(vCode.getCode()+" >"+path);
148 | vCode.write(path);
149 | } catch (IOException e) {
150 | e.printStackTrace();
151 | }
152 | }
153 | }
154 |
155 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ScnuWang/SpringBoot/dab0a4c95389a69f3dbaadb09d28741e4d706c66/springsecurity4/src/main/resources/application.properties
--------------------------------------------------------------------------------
/springsecurity4/src/main/resources/templates/CSRFTest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CSRF测试
5 |
6 |
7 |
8 | 这里是CSRF测试页!!!
9 |
10 |
16 |
17 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/resources/templates/admin.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ADMIN
5 |
6 |
7 |
8 | 这里是ADMIN页面!!!!!
9 |
10 | 访问:
11 | 首页
12 | 普通用户页面
13 | VIP用户页面
14 | 管理员页面
15 | 超级管理员页面
16 |
17 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/resources/templates/deny.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 403
5 |
6 |
7 |
8 |
9 | 请求异常信息:
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/resources/templates/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | HOME
5 |
6 |
7 |
8 | 这里是首页!!!
9 |
10 |
11 |
14 |
15 | 访问:
16 | 首页
17 | 普通用户页面
18 | VIP用户页面
19 | 管理员页面
20 | 超级管理员页面
21 |
22 | 注册
23 | 登录
24 |
25 |
26 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/resources/templates/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 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/resources/templates/regist.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 注册
5 |
6 |
7 |
8 |
14 |
15 | 异常信息
16 |
17 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/resources/templates/super.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SUPER
5 |
6 |
7 |
8 |
9 | 这里是SUPER用户的页面!!!
10 |
11 | 访问:
12 | 首页
13 | 普通用户页面
14 | VIP用户页面
15 | 管理员页面
16 | 超级管理员页面
17 |
18 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/resources/templates/user.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | USER
5 |
6 |
7 |
8 | 这里是普通注册用户的页面!!!
9 | 访问:
10 | 首页
11 | 普通用户页面
12 | VIP用户页面
13 | 管理员页面
14 | 超级管理员页面
15 |
16 |
17 |
--------------------------------------------------------------------------------
/springsecurity4/src/main/resources/templates/vip.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | VIP
5 |
6 |
7 |
8 |
9 | 这里是VIP页面!!!
10 |
11 | 访问:
12 | 首页
13 | 普通用户页面
14 | VIP用户页面
15 | 管理员页面
16 | 超级管理员页面
17 |
18 |
--------------------------------------------------------------------------------
/springsecurity4/src/test/java/cn/geekview/Springsecurity4ApplicationTests.java:
--------------------------------------------------------------------------------
1 | package cn.geekview;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class Springsecurity4ApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------