SpringSecurity使用

目录

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下面已经提供
SpringSecurity使用
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);

SpringSecurity使用
首先保证项目已经配置了数据源
SpringSecurity使用
新建自动配置类,替换默认的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);
    }
}

启动项目,数据库中就会添加用户的信息和权限
SpringSecurity使用
SpringSecurity使用

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;
    }
}
上一篇:Day46_Spring Security—Spring Security的Web使用(尚硅谷)


下一篇:SpringSecurity-1-UserDetailsService接口