使用Spring Security实现注册、登录、退出
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
配置数据源
# 数据源 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root spring.datasource.password=root spring.datasource.url=jdbc: mysql://localhost:3306/songs?serverTimezone=UTC # 别名 mybatis.type-aliases-package=com.xiang.entity # mapper路径 mybatis.mapper-locations=classpath:com.xiang.dao/*.xml
编写实体类
// Lombok @Data public class User implements UserDetails{ private String username; private String password; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
接口
@Mapper public interface UserMapper { void AddUser(@Param("username") String username,@Param("password") String password); User findOneByUsername(@Param("username") String username); }
在resources目录下创建与dao接口包名相同的目录,并创建UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xiang.dao.UserMapper"> <insert id="AddUser"> insert into users(username,password) values(#{username},#{password}); </insert> <select id="findOneByUsername" resultType="user"> select username,password from users where username=#{username}; </select> </mapper>
编写service层
@Service public class UserService implements UserDetailsService{ @Autowired private UserMapper userMapper; @Autowired private PasswordEncoder passwordEncoder; public boolean register(User user){ //保存到数据库 try{ userMapper.AddUser(user.getUsername(),passwordEncoder.encode(user.getPassword())); }catch (Exception e){ System.out.println(e.fillInStackTrace()); return false; } return true; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userMapper.findOneByUsername(username); } }
编写controller层
编写Spring Security配置类
- 重写configure(HttpSecurity http)方法配置拦截策略
@Configuration public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/user/registerPage","/user/register","/user/loginPage","/user/login").permitAll() .anyRequest().authenticated() .and() .httpBasic() .and() .formLogin() .loginPage("/user/loginPage") //登录页面url .loginProcessingUrl("/user/login") //登录表单的action路径 //登录成功后的路径,默认返回templates目录下的index.html页面 .defaultSuccessUrl("/user/index")//登录成功后跳转的路径.successForwardUrl("/user/index")登录成功后重定向的路径 .and() .logout() .logoutUrl("/user/logout") .logoutSuccessUrl("/user/loginPage"); } }
- 重写configure(HttpSecurity http)方法配置拦截策略
编写注册页面、登录页面
- 注册页面主要部分
<form th:action="@{/user/register}" method="post"> <!--如果开启了CSRF防护功能,需要添加一个隐藏的域,才可以使用post方式提交,否则会被拦截 --> <input type="hidden" name="_csrf" value="af53a1c2-b2b0-4f92-9907-80555a2329ac"> <input type="text" name="username"> <input type="password" name="password"> <input type="submit" value="Register"> </form>
- 注册页面主要部分
登录页面主要部分
<form th:action="@{/login}" method="post"> <input type="text" name="username"> <input type="password" name="password"> <input type="submit" value="Login in"> </form>
退出页面主要部分
<form th:action="@{/user/logout}" method="post"> <input type="submit" value="Logout"> </form>
注
- Spring Security3.2开始,默认开启CSRF(跨站请求伪造)防护。通过一个同步token来实现CSRF防护功能,会拦截状态变化的请求并检查CSRF token:如果请求中不包含token或者token与服务器不匹配的话,请求就会失败。
- 所有的post请求必须在一个"_csrf"域中提交token。
在form标签中使用th:action="@{/user/register}"设置提交路径,就会自动生成一个"_csrf"隐藏域。
关闭CSRF防护功能(不推荐)
http.csrf().disable();//禁用CSRF防护功能