Spring Security 学习之旅开始
SpringSecurity 开始
我的项目:Github
1. 引入依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.1</version> <relativePath/> </parent> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
在manven依赖仓库中:
2. 配置Security
1.在包下创立SecurityCconfig类,重写configure办法,其中WebSecurity web,能够定义疏忽门路
@Override public void configure(WebSecurity web) throws Exception { //疏忽拦挡 web.ignoring().antMatchers("/sayHello","/doLogin"); }
- HttpSecurity http 能够拦挡申请,能够定义登录、登出等等
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests()//开启登录 //示意拜访,ex/index 这个接口,须要具备admin角色 .antMatchers("/es/**").hasRole("admin") //示意残余的其余接口,登录之后能拜访 .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") //登录解决接口 .loginProcessingUrl("/doLogin") //定义登录时,用户名的key,默认为username .usernameParameter("username") //定义登录时,用户明码的key,默认为password .passwordParameter("password") //定义登录胜利的处理器 .successHandler(new AuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); response.sendRedirect("/success.html");//重定向到一个页面 MyUserDetails detail= (MyUserDetails)authentication.getPrincipal(); System.out.println(detail); } }) .failureHandler(new AuthenticationFailureHandler() { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); ResponseBean responseBean = ResponseBean.sendByCode("you have login failure !", 401); String result = new ObjectMapper().writeValueAsString(responseBean); out.write(result); out.flush(); } }) //和表单登录相干的接口通通都间接通过 .permitAll() .and() .logout() .logoutUrl("/logout") .logoutSuccessHandler(new LogoutSuccessHandler() { @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); out.write("you have login out success !"); out.flush(); } }) .permitAll() .and() .httpBasic() .and() .csrf().disable(); }
简略的表单登录配置,这里的logou是Get申请,若要Post申请,则减少一行
logoutRequestMatcher(new AntPathRequestMatcher("/logout","POST"))
and相当于ssm中标签的完结,permitAll示意登录相干的页面、操作不要拦挡。
- 定义明码加密
因为security自带盐,用明文加密的都不一样,省去了咱们很多工夫。
@Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); }
- 引入JPA依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- jpa --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency>
- 创立Use类
@Data@Entity(name = "t_user")public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String username; private String password; private Integer enabled; private Integer locked;}
- 创立Role类,为MyDetail作筹备
@Data@Entity(name = "t_role")public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; private String chineseName;}
- 创立MyDetail类,实现UserDetail
@Datapublic class MyUserDetails implements UserDetails { private User user; private List<Role> roles; @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> authorities = new ArrayList<>(); if (roles != null && roles.size() > 0) { for (Role role : roles) { authorities.add(new SimpleGrantedAuthority(role.getName())); } } return authorities; } @Override public String getPassword() { return user == null ? null : user.getPassword(); } @Override public String getUsername() { return user == null ? null : user.getUsername(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { Integer locked = user.getLocked(); if (locked == 0) { return true; } return false; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { Integer enabled = user.getEnabled(); if (enabled == 1) { return true; } return false; } @Override public String toString() { return "MyUserDetails{" + "user=" + user + ", roles=" + roles + '}'; }}
- 编写注入实体办法
在测试类中,创建对象,jpa会主动去创建表格。做一个示范,因为学习,我先创立的表格,你们能够少走弯路了。比方上面这样:
实体,加注解
@Data@Entity(name = "t_hill_heavy")public class HillHeavy { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String username; private Boolean handsome; private String gender; private Integer high; private boolean rich;
创立Dao
public interface HillHeavyDao extends JpaRepository<HillHeavy,Integer> { /** * 查问 * @param username 用户名 * @author 山沉 * @date 2020/12/28 22:42 * @return {@link HillHeavy} */ HillHeavy findHillHeavyByUsername(String username);}
在测试类中:
@SpringBootTestclass EsSearchApplicationTests { private static final Logger logger = LoggerFactory.getLogger(EsSearchApplicationTests.class); @Resource private HillHeavyDao hillHeavyDao; @Test void contextLoads() { HillHeavy hillHeavy = new HillHeavy(); hillHeavy.setUsername("山沉"); hillHeavy.setHandsome(true); hillHeavy.setHigh(180); hillHeavy.setGender("男"); hillHeavy.setRich(true); hillHeavyDao.save(hillHeavy); logger.info("实体----->{}",hillHeavy); }}
这样在用dao层去注入实体,在数据库中,也会生成表格,数据。如下:
是有点自恋,啊。原谅想帅的小瘦子。
- 有了表构造,在UserServiceImpl类,去实现UserDetailService类,重写
loadUserByUserName(String username)
在此办法中,从数据库中依据username,查问出用户,角色,返回UserDetail对象。
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userMapper.selectUser(username); MyUserDetails details = new MyUserDetails(); if(user == null){ throw new BadCredentialsException("this username or password is not true!"); } details.setUser(user); Integer id = user.getId(); List<Role> roles = userMapper.selectRole(id); details.setRoles(roles); return details; }
3. 测试登录
到此,咱们的表单登录,就胜利了。通过doLogin登录,携带user信息,进入UsernamePasswordAuthenticationFilter
中,注入用户信息。在从表中取得用户信息与之比照,而后通过登录胜利或失败返回给前端JSON格局。
在这里说下,successHandler
是比拟弱小的,在外面能够作重定向,也能够获取用户信息,等等。集成 defaultSuccessUrl() successForwardUrl()
。
defaultSuccessUrl
能够指定登录胜利的跳转页面,比方输出welcome/say
,来到login.html
页面。登录胜利后,会来的welcome/say
。sccessForwardUrl
指定登录胜利后,到那里。不论登录前你操作的哪一个接口,胜利后一律到指定的门路。
测试登录