# springboot_springsecurity
**Repository Path**: stefanpy/springboot_springsecurity
## Basic Information
- **Project Name**: springboot_springsecurity
- **Description**: springboot 整合spring security
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: dev
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 2
- **Created**: 2018-05-18
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
springboot 整合 Spring Security
第一步:加入依赖
```
org.springframework.boot
spring-boot-starter-security
```
一旦引入这个依赖,spring boot项目就默认开启了 security的默认保护。访问任何请求都会跳转到/login ,默认显示一个登录页面,但是我们并不知道用户名和密码。
用户名默认是user,密码是加密的 在运行后台可以找到,默认是打印到后来的。
第二步:java 配置类
```
package com.young.security.mysecurity.config;
import com.young.security.mysecurity.security.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.sql.DataSource;
/**
* Create by stefan
* Date on 2018-05-17 21:23
* Convertion over Configuration!
*/
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,jsr250Enabled = true,prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private MyUserDetailService myUserDetailService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//1.启用内存用户存储
// auth.inMemoryAuthentication()
// .withUser("xfy").password(passwordEncoder().encode("1234")).roles("ADMIN").and()
// .withUser("tom").password(passwordEncoder().encode("1234")).roles("USER");
//2.基于数据库表进行验证
// auth.jdbcAuthentication().dataSource(dataSource)
// .usersByUsernameQuery("select username,password,enabled from user where username = ?")
// .authoritiesByUsernameQuery("select username,rolename from role where username=?")
// .passwordEncoder(passwordEncoder());
//3.配置自定义的用户服务
auth.userDetailsService(myUserDetailService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().loginPage("/signIn").loginProcessingUrl("/user/userLogin") //自定义登录页面、登录请求路由
.and()
.logout().logoutSuccessUrl("/signIn")// 设置登出,登出成功后跳转到登录页面
.and()
.authorizeRequests() //开始请求的配置
.antMatchers("/signIn","/hello").permitAll() // premitAll()不做拦截
.antMatchers("/index").authenticated() //authenticated() 必须登录后可见
.antMatchers("/demo").permitAll()
.antMatchers("/admin/**","/add").hasRole("ADMIN") //有ADMIN角色
.regexMatchers("/admin1/.*").access("hasRole('ADMIN') or hasRole('ADMIN1')")
.anyRequest().authenticated()
.and()
.requiresChannel().antMatchers("/add").requiresSecure()//https://127.0.0.1:8443/add 将http转为https
.and()
.rememberMe().tokenValiditySeconds(2419200).tokenRepository(persistentTokenRepository()).alwaysRemember(true);// 启用记住我
}
// 记住我,将用户信息存入数据库
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
//tokenRepository.setCreateTableOnStartup(true);
return tokenRepository;
}
//注册密码加密处理器
@Bean
public static PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
```
**自定义UserDetailsService**
```
package com.young.security.mysecurity.security;
import com.young.security.mysecurity.pojo.Role;
import com.young.security.mysecurity.pojo.User;
import com.young.security.mysecurity.repository.RoleRepository;
import com.young.security.mysecurity.repository.UserRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* Create by stefan
* Date on 2018-05-17 22:49
* Convertion over Configuration!
*/
@Component
@Slf4j
public class MyUserDetailService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
User user = userRepository.findByUsername(name);
if (user==null){
throw new AuthenticationCredentialsNotFoundException("authError");
}
log.info("{}",user);
List role = roleRepository.findByUsername(name);
log.info("{}",role);
List authorities = new ArrayList<>();
role.forEach(role1 -> authorities.addAll(AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_"+role1.getRolename())));
log.info("{}",authorities);
return new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),authorities);
}
}
```
### 使用注解保护
#### 开启注解
```
@EnableGlobalMethodSecurity(securedEnabled = true,jsr250Enabled = true,prePostEnabled = true)
```
#### 注解示意:
```
@Secured({"ADMIN","ADMIN1"})
@RolesAllowed({"ADMIN","ADMIN1"})
使用方式相似,RolesAllowed更正式
```
```
@PreAuthorize("hasRole('ADMIN') AND hasRole('ADMIN1')") 的string参数是一个SpEL表达式
@PreAuthorize("hasRole('ADMIN') and #user.username.length() <=6") 可获得参数
@PostAuthorize("returnObject.username == principal.username") 可获得返回值
过滤方法
@PostFilter("hasRole('ADMIN') || filterObject.username == principal.username") 这个可直接获得方法的返回值列表的单个元素filterObject,不需要加#
@PreFilter("hasRole('ADMIN') || #filterObject.endsWith('admin')") 加#filterObject可获得传入参数列表的单个元素
```
视图保护(Thymeleaf)
第一步:引入依赖
```
org.springframework.boot
spring-boot-starter-thymeleaf
org.thymeleaf.extras
thymeleaf-extras-springsecurity4
```
第二步:在视图页声明:
```
```
第三步使用:
```
hello someone !
会员admin可见
会员admin\ADMIN1可见
admin中心
admin1中心
```
个人详细笔记整理:
[让Spring Security 来保护你的Spring Boot项目吧](https://www.jianshu.com/p/6df285f30a79)
**参考资料:**
- 书籍:Spring实战(第4版) 第9章和第14章
- [Spring Security 参考手册](https://springcloud.cc/spring-security-zhcn.html)
- [初识 Spring Security](https://note.youdao.com/)
- [程序猿DD的Spring Security学习笔记](http://blog.didispace.com/tags/Spring-Security/)
*Spring Security 的使用才刚刚开始。*