目录
SpringSecurity使用
springboot添加依赖
<!--security认证授权-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
自定义登录用户和密码
在配置文件中添加
spring.security.user.name= liufucheng
spring.security.user.password= 123456
关闭SpringSecurity
在启动了上排除Security
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class Springbootdome2Application {
public static void main(String[] args) {
SpringApplication.run(Springbootdome2Application.class, args);
}
}
用户授权
用户授权主要是通过UserDetailsService 的子类来实现的
1.inMemoryAuthentication(缓存)
2.JdbcUserDetailsManager(数据库)
通过缓存授权
定义授权配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启注解方式认证
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 指定加密方式
*/
@Bean
public PasswordEncoder passwordEncoder(){
// 使用BCrypt加密密码
return new BCryptPasswordEncoder();
}
//授权
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().
passwordEncoder(passwordEncoder()) //设置密码加密方式
.withUser("root").password(passwordEncoder().encode("123456")).roles("level1","level2","level3")
.and()
.withUser("liufucheng").password(passwordEncoder().encode("123456")).roles("level1","level2")
.and()
.withUser("xiaoliu").password(passwordEncoder().encode("123456")).roles("level3")
.and();
}
}
通过数据库授权
定义UserDetailsService的实现类
@Component("SecurityUserDetailService")
public class SecurityUserDetailService implements UserDetailsService {
@Autowired
UserInfoMapper userInfoMapper;
@Autowired
UserRoleMapper userRoleMapper;
@Autowired
RoleInfoMapper roleInfoMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo=null; //自定义的用户
User user=null; //springSecurity的内置用户
if(username!=null){
//根据用户名查询用户信息
UserInfoExample userInfoExample = new UserInfoExample();
UserInfoExample.Criteria criteria = userInfoExample.createCriteria();
criteria.andNameEqualTo(username);
List<UserInfo> userInfos =userInfoMapper.selectByExample(userInfoExample);
if(userInfos.size()>0){
userInfo=userInfos.get(0);
//根据用户id查询用户的角色id
UserRoleExample userRoleExample = new UserRoleExample();
UserRoleExample.Criteria criteria1 = userRoleExample.createCriteria();
criteria1.andUserIdEqualTo(userInfo.getId());
List<UserRole> userRoles = userRoleMapper.selectByExample(userRoleExample);
List<GrantedAuthority> list=null;
if(userRoles.size()>0){
list=new ArrayList<>();
//遍历用户的角色id
for (UserRole userRole: userRoles) {
//根据用户的角色id查询用户的角色
RoleInfo roleInfo = roleInfoMapper.selectByPrimaryKey(userRole.getRoleId());
//springSecurity的角色都有统一的前缀“ROLE_”
GrantedAuthority role = new SimpleGrantedAuthority("ROLE_"+roleInfo.getRoleName());
list.add(role);
}
}
//userInfo的密码必须与配置类设置的密码加密方式一致
user = new User(userInfo.getName(),userInfo.getPassword(),list);
}
}
return user;
}
}
定义授权配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //使用注解方式认证
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("SecurityUserDetailService")
private UserDetailsService userDetailsService;
//授权
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).
passwordEncoder(new BCryptPasswordEncoder());
}
}
用户认证
方式一:注解方式
注解方式必须在配置类SecurityConfig中添加@EnableGlobalMethodSecurity(prePostEnabled = true)
然后在接口上添加@PreAuthorize注解来指定可以访问接口的角色
@RequestMapping("/findUser")
@PreAuthorize("hasAnyRole('level1','level2')")
@ResponseBody
public Object findUser(){
UserInfo userInfo = userInfoMapper.selectByPrimaryKey(1);
return userInfo;
}
方式二:设置规则
在WebSecurityConfigurerAdapter 实现类中设置规则
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //使用注解方式认证
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//认证
@Override
protected void configure(HttpSecurity http) throws Exception {
// super.configure(http);
//请求受权的规则
http.authorizeRequests()
.antMatchers("/","/index","/toLogin","/login","/mylogin.html").permitAll()
.antMatchers("/level1/**").hasRole("level1")
.antMatchers("/level2/**").hasRole("level2")
.antMatchers("/level3/**").hasRole("level3");
}
}
方式三:替换默认的userDetailsService
InMemoryUserDetailsManager缓存方式
新建自动配置类,替换默认的userDetailsService
@Configuration
public class SecurityAutoConfig {
/**
* 指定加密方式
*/
@Bean
public PasswordEncoder passwordEncoder(){
// 使用BCrypt加密密码
return new BCryptPasswordEncoder();
}
/**
* 基于内存的认证方式
*
* @return
*/
@Bean
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("root").password(passwordEncoder().encode("123456")).roles("level1","level2").build());
manager.createUser(User.withUsername("liufucheng").password(passwordEncoder().encode("123456")).roles("level2").build());
manager.createUser(User.withUsername("xiaoliu").password(passwordEncoder().encode("123456")).roles("level3").build());
return manager;
}
}
配置自定义的userDetailsService
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
//认证
@Override
protected void configure(HttpSecurity http) throws Exception {
http.userDetailsService(userDetailsService);
}
}
JdbcUserDetailsManager数据库方式
首先在项目中找到users.ddl文件,在数据库中执行文件中的创建表的sql语句,数据类型不匹配需要自己手动修改一下,修改后的sql下面已经提供
sql
CREATE TABLE users(username VARCHAR(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR(500) NOT NULL,enabled BOOLEAN NOT NULL);
CREATE TABLE authorities (username VARCHAR(50) NOT NULL,authority VARCHAR(50) NOT NULL,CONSTRAINT fk_authorities_users FOREIGN KEY(username) REFERENCES users(username));
CREATE UNIQUE INDEX ix_auth_username ON authorities (username,authority);
首先保证项目已经配置了数据源
新建自动配置类,替换默认的userDetailsService,这里创建的用户会被新增到数据库中,需要引入数据源
@Configuration
public class SecurityAutoConfig {
@Autowired
DataSource dataSource;
/**
* 指定加密方式
*/
@Bean
public PasswordEncoder passwordEncoder(){
// 使用BCrypt加密密码
return new BCryptPasswordEncoder();
}
/**
* 基于内存的认证方式
*
* @return
*/
@Bean
public UserDetailsService userDetailsService() {
JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);
if( !manager.userExists("root")){ //数据库中已经存在的用户,在项目重新启动时不能再添加,否则数据库会出现主键重复,项目无法启动
manager.createUser(User.withUsername("root").password(passwordEncoder().encode("123456")).roles("level1","level2").build());
}
if( !manager.userExists("liufucheng")){
manager.createUser(User.withUsername("liufucheng").password(passwordEncoder().encode("123456")).roles("level2").build());
}
if( !manager.userExists("xiaoliu")){
manager.createUser(User.withUsername("xiaoliu").password(passwordEncoder().encode("123456")).roles("level3").build());
}
return manager;
}
}
配置自定义的userDetailsService
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
//认证
@Override
protected void configure(HttpSecurity http) throws Exception {
http.userDetailsService(userDetailsService);
}
}
启动项目,数据库中就会添加用户的信息和权限
springboot+springsecurity+thymeleaf整合
pom.xml依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springbootdome2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootdome2</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!-- mybatis逆向工程jar包 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.4</version>
</dependency>
<!--security认证授权-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--thymeleaf引擎模板-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--对Thymeleaf添加Spring Security标签支持-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<overwrite>true</overwrite>
<!--逆向工程generatorConfig.xml文件位置-->
<configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile>
</configuration>
</plugin>
</plugins>
</build>
</project>
项目配置
server.port=8081
#数据库连接配置
spring.datasource.url=jdbc:mysql://11.110.111.82:3306/sweetinn?characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=hh
spring.datasource.password=123456
#mybatis整合
mybatis.type-aliases-package=com.example.demo.pojo
mybatis.mapper-locations= classpath:mapper/*.xml
logging.level.com.example.demo.dao=debug
#关闭thymeleaf缓存
spring.thymeleaf.cache=false
自定义userDetailsService(我这使用的是本博客的用户认证方式三的JdbcUserDetailsManager数据库方式)
@Configuration
public class SecurityAutoConfig {
@Autowired
DataSource dataSource;
/**
* 指定加密方式
*/
@Bean
public PasswordEncoder passwordEncoder(){
// 使用BCrypt加密密码
return new BCryptPasswordEncoder();
}
/**
* 基于内存的认证方式
*
* @return
*/
@Bean
public UserDetailsService userDetailsService() {
JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);
if( !manager.userExists("root")){ //数据库中已经存在的用户,在项目重新启动时不能再添加,否则数据库会出现主键重复,项目无法启动
manager.createUser(User.withUsername("root").password(passwordEncoder().encode("123456")).roles("level1","level2").build());
}
if( !manager.userExists("liufucheng")){
manager.createUser(User.withUsername("liufucheng").password(passwordEncoder().encode("123456")).roles("level2").build());
}
if( !manager.userExists("xiaoliu")){
manager.createUser(User.withUsername("xiaoliu").password(passwordEncoder().encode("123456")).roles("level3").build());
}
return manager;
}
}
配置认证和授权
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
//认证
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/index","/toLogin","/login").permitAll()
.antMatchers("/level1/**").hasRole("level1")
.antMatchers("/level2/**").hasRole("level2")
.antMatchers("/level3/**").hasRole("level3");
http.formLogin().loginPage("/toLogin") //指定自定义的登录页面
.usernameParameter("name") //指定自定义的登录页面用户名
.passwordParameter("passwd") //指定自定义的登录页面密码
.loginProcessingUrl("/toLogin");//表单提交的路径
http.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
}
登录页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<div style="text-align: center">
登录
<form th:action="@{/toLogin}" method="post">
登录名:<input name="name" /> <br/>
密码:<input type="password" name="passwd"/><br/>
<input type="checkbox" name="jzw"> 记住我<br/>
<input type="submit" />
</form>
</div>
</body>
</html>
登陆后的页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<div sec:authorize="!isAuthenticated()">
<a th:href="@{/toLogin}">登录</a>
</div>
<div sec:authorize="isAuthenticated()">
用户名:<span sec:authentication="principal.username"></span>
角色:<span sec:authentication="principal.authorities"></span>
<a th:href="@{/logout}">注销</a>
</div>
</div>
<div sec:authorize="hasRole('level1')">
<a th:href="@{/level1/page/1}">level1-page1</a>
<a th:href="@{/level1/page/2}">level1-page2</a>
<a th:href="@{/level1/page/3}">level1-page3</a>
</div>
<div sec:authorize="hasRole('level2')">
<a href="/level2/page/1">level2-page1</a>
<a href="/level2/page/2">level2-page2</a>
<a href="/level2/page/3">level2-page3</a>
</div>
<div sec:authorize="hasRole('level3')">
<a href="/level3/page/1">level3-page1</a>
<a href="/level3/page/2">level3-page2</a>
<a href="/level3/page/3">level3-page3</a>
</div>
</body>
</html>
controller接口
@Controller
public class IndexController {
@RequestMapping({"/","/index"})
public String home(String name,String passwd,boolean jzw,Model model){
return "home/home";
}
@RequestMapping("/toLogin")
public String login(Model model){
return "mylogin";
}
@RequestMapping("/level1/page/{id}")
public String level1(@PathVariable("id") int id){
return "level1/page"+id;
}
@RequestMapping("/level2/page/{id}")
public String level2(@PathVariable("id") int id){
return "level2/page"+id;
}
@RequestMapping("/level3/page/{id}")
public String level3(@PathVariable("id") int id){
return "level3/page"+id;
}
}