第13章 Spring Boot Security详解

spring-boot-starter-security是对Spring Security的一个封装,具体如下

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
进入里面的  文件:
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starters</artifactId>  //父类是spring-boot-starters
		<version>1.5.3.RELEASE</version>
	</parent>
	<artifactId>spring-boot-starter-security</artifactId>

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId> //加入的起步依赖,spring-boot-starter
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId> //加入了 aop
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId> //封装了security-config,移除aop
			<exclusions>
				<exclusion>
					<groupId>aopalliance</groupId>
					<artifactId>aopalliance</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId> //封装了security-web,移除aop
			<exclusions>
				<exclusion>
					<groupId>aopalliance</groupId>
					<artifactId>aopalliance</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

pom.xml

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>   // 开始 security
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId> //开始 thymeleaf 依赖
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId> // 开始 web
		</dependency>

		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-springsecurity4</artifactId> //模板 和 security整合
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId> //开始 测试
			<scope>test</scope>
		</dependency>

		<!--  sql-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId> //开始 JPA 
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId> //mysql 驱动
		</dependency>
	</dependencies>

配置Spring Security 的AuthenticationManagerBuilder

@EnableWebSecurity  //1 开启 webSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter { //2 继承配置类 WebSecurityConfigurerAdapter

	@Autowired  //3 注入 AuthenticationManagerBuilder
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser("forezp").password("123456").roles("USER") ;
		//4 具体的配置, 内存级别的,用户名 密码 角色
	}

集成了 getRemoteUser() getUserPrincipal() login(string,string) logout() API

HttpSecurity 哪些需要认证,哪些不需要认证


@EnableWebSecurity
@Configuration   //指出这个类是配置类
@EnableGlobalMethodSecurity(prePostEnabled = true)   //开户方法验证
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()   //认证的请求,开始匹配
                .antMatchers("/css/**", "/index").permitAll()   //所有css 请求和 index 放行
                .antMatchers("/user/**").hasRole("USER")   //所有user请求,和 blogs 请求,需要 user权限
                .antMatchers("/blogs/**").hasRole("USER")
                .and()
                .formLogin().loginPage("/login").failureUrl("/login-error") //登录的请求是login,失败的请求是 login-error
                .and()
                .exceptionHandling().accessDeniedPage("/401");  //异常拒绝的请求是 /401
        http.logout().logoutSuccessUrl("/");   //登录成功的请求是 / 
    }

配置application.yml

spring:
  thymeleaf:
    mode: HTML5
    encoding: UTF-8
    cache: false

action

@Controller
public class MainController {

	@RequestMapping("/")
	public String root() {
		return "redirect:/index";  //重定向
	}

	@RequestMapping("/index")
	public String index() {
		return "index";
	}

	@RequestMapping("/user/index")
	public String userIndex() {
		return "user/index";
	}

	@RequestMapping("/login")
	public String login() {
		return "login";
	}

	@RequestMapping("/login-error")
	public String loginError(Model model) {
		model.addAttribute("loginError", true);  //在Model 放 数据
		return "login";
	}
	@GetMapping("/401")
	public String accesssDenied() {
		return "401";
	}
}

login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>Login page</title>
        <meta charset="utf-8" />
        <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />  //用了模板,直接 th:href="@{}"
	</head>
    <body>
        <p th:if="${loginError}" class="error">用户名或密码错误</p>   //取出 放置的错误 信息  如果存在的话  
        <form th:action="@{/login}" method="post">    //th:action="@{}"  提交的地址
            <label for="username">用户名</label>:
            <input type="text" id="username" name="username" autofocus="autofocus" /> <br />
            <label for="password">密码</label>:
            <input type="password" id="password" name="password" /> <br />
            <input type="submit" value="登录" />  //提交
        </form>
        <p><a href="/index" th:href="@{/index}">返回首页</a></p> //返回到首页
    </body>
</html>

index.html

        <div th:fragment="logout"  sec:authorize="isAuthenticated()">
            登录用户: <span sec:authentication="name"></span> |   //登录用户
            用户角色: <span sec:authentication="principal.authorities"></span>  //角色
            <div>
                <form action="#" th:action="@{/logout}" method="post">   //退出的请求是 post
                    <input type="submit" value="登出" />
                </form>
            </div>
        </div>

        <ul>
            <li>点击<a href="/user/index" th:href="@{/user/index}">去/user/index保护的界面</a></li>
        </ul>

user/index.html

        <div th:substituteby="index::logout"></div>   //使用 index页面中 logout 片段
        <h1>这个界面是被保护的界面</h1>
        <p><a href="/index" th:href="@{/index}">返回首页</a></p>
        <p><a  href="/blogs" th:href="@{/blogs}">管理博客</a></p>

401.html

		<div sec:authorize="isAuthenticated()">   //这里和上面的一样,使用片段 也挺好的
			<p>已有用户登录</p>
			<p>用户: <span sec:authentication="name"></span></p>
 			<p>角色: <span sec:authentication="principal.authorities"></span></p>
		</div>
 		<div sec:authorize="isAnonymous()">    //未登录 直接访问401.html
			<p>未有用户登录</p>
		</div>
		<p>
			拒绝访问!
		</p>

使用 th sec 标签要引入 >xmlns:sec=“http://www.thymeleaf.org/thymeleaf-extras-springsecurity4”>

第二版,配置类中 使用简单的userDetailsService

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());
    }

	@Bean
	public UserDetailsService userDetailsService() {
		InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); // 在内存中存放用户信息
		manager.createUser(User.withUsername("forezp").password("123456").roles("USER").build());
		manager.createUser(User.withUsername("admin").password("123456").roles("USER","ADMIN").build());
		return manager;
	}

开启方法级别的保护

@EnableGlobalMethodSecurity(prePostEnabled = true)

意思是 @PreAuthorize 和 @PostAuthorize 是否可用
@PreAuthorize(“hasRole(‘ADMIN’,’******’)”)
@PreAuthorize(“hasAuthorize(‘ROLE_ADMIN’,’******’)”)

测试方法级别的保护

public class Blog {
    private Long id;
    private String name;
    private String content;
public interface IBlogService {
    List<Blog> getBlogs();
    void deleteBlog(long id);
}
@Service
public class BlogService implements IBlogService {

    private List<Blog> list=new ArrayList<>();  //List 存储

    public BlogService(){
        list.add(new Blog(1L, " spring", "good!"));   //加入数据
        list.add(new Blog(2L,"spring boot", "nice!"));
    }

    @Override
    public List<Blog> getBlogs() {   //获得数据
        return list;
    }

    @Override
    public void deleteBlog(long id) {  //删除
        Iterator iter = list.iterator();  //先取得Iterator
        while(iter.hasNext()) {  // 如果有下一个,取出,并且和id比较
            Blog blog= (Blog) iter.next();
            if (blog.getId()==id){
                iter.remove();
            }
        }
    }
}

@RestController
@RequestMapping("/blogs")
public class BlogController {
    @Autowired
    BlogService blogService;
    @GetMapping
    public ModelAndView list(Model model) {
        List<Blog> list =blogService.getBlogs();
        model.addAttribute("blogsList", list);
        return new ModelAndView("blogs/list", "blogModel", model);  //跳转页面,为model起名字,放入的model
    }

    @PreAuthorize("hasAuthority('ROLE_ADMIN')")  //在之前就校验 是否 有权限
    @GetMapping(value = "/{id}/deletion")
    public ModelAndView delete(@PathVariable("id") Long id, Model model) {
        blogService.deleteBlog(id);
        model.addAttribute("blogsList", blogService.getBlogs());
        return new ModelAndView("blogs/list", "blogModel", model);
    }
}
    <table >
        <thead>
        <tr>
            <td>博客编号</td>
            <td>博客名称</td>
            <td>博客描述</td>
        </tr>
        </thead>
        <tbody>
        <tr th:each="blog: ${blogModel.blogsList}">   //取出model,中 的 list 放在 blog 中
            <td th:text="${blog.id}"></td>
            <td th:text="${blog.name}"></td>
            <td th:text="${blog.content}"></td>
            <td>
                <div >
                    <a th:href="@{'/blogs/' + ${blog.id}+'/deletion'}">
                        删除
                    </a>
                </div>
            </td>
        </tr>
        </tbody>
    </table>

JPA

1,引入依赖(jpa 数据库驱动)
2,配置数据库连接属性  和 数据库ddl 生成方式
3,写 Entity类 

security:
  user:
    name: lisi
    password: 123456
    role: USER
  basic:
    enabled: true   //设置为false就关闭了,在没有配置 WebSecurityConfigurerAdapter的情况下


update 如果启动时表格式不一致则更新表,原有数据保留
create  启动时删数据库中的表,然后创建,退出时不删除数据表 
create-drop 启动时删数据库中的表,然后创建,退出时删除数据表  如果表不存在报错  
validate  项目启动表结构进行校验  如果不一致则报错

删除意思:sessionFactory一关闭,表就自动删除(hibernate


User

@Entity
public class User implements UserDetails, Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    private String username;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
    private List<Role> authorities;

    @Column
    private String password;

    public User() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    public void setAuthorities(List<Role> authorities) {
        this.authorities = authorities;
    }

    @Override
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }


}

role

@Entity
public class Role implements GrantedAuthority {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column(nullable = false)
	private String name;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@Override
	public String getAuthority() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return name;
	}
}

service dao

public interface UserDao extends JpaRepository<User, Long>{
	User findByUsername(String username);
}

@Service
public class UserService implements UserDetailsService {
    @Autowired
    private UserDao userRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return userRepository.findByUsername(username);
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq120631157/article/details/82996768