第13章 Spring Boot Security详解

xiaoxiao2021-07-06  524

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); } }

转载请注明原文地址: https://www.6miu.com/read-4821486.html

最新回复(0)