基于springsecurity的登录注册demo

发布时间:2019-10-12
技术:springboot+springsecurity+jpa+mysql

概述

基于springsecurity的登录注册demo, 包含验证码功能, 记住我. 代码简洁, 注释通俗易懂, 便于初学者上手.

详细

一、需求(要做什么)

我们要基于springSecurity实现用户的登录注册功能, 代码要简洁, 通俗易懂, 便于初学者上手.

二、理论概述

Spring Security一个能够为基于Spring的企业应用系统提供声明式的安全訪问控制解决方式的安全框架(简单说是对访问权限进行控制嘛),应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。

Spring Security核心就是一系列的过滤器链,当一个请求来的时候,首先要通过过滤器链的校验,校验通过之后才会访问用户各种信息。 

image.png

     

三、代码分析

我们把验证码的拦截器,放在UsernamePasswordAuthenticationFilter之前. 

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	
	
	/**
	 * 配置这个相当于               前端 加密的密码         和      数据库加密          都      必须用这个
	 * @return
	 */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
	
	@Autowired
	private DataSource dataSource;
	
	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl  tokenRepository=new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        //第一次创建开启
        //tokenRepository.setCreateTableOnStartup(true); 
		return tokenRepository;
	}
	
	@Autowired
	MyUserDetailsService  myUserDetailsService;
	
	
	@Autowired
	SecurityProperties  securityProperties;
	
	@Autowired
	MyAuthenticationSuccessHandler  myAuthenticationSuccessHandler;
	
	@Autowired	
	MyAuthenticationFailureHandler  myAuthenticationFailureHandler;
	
	@Autowired	
	MyLogoutSuccessHandler  myLogoutSuccessHandler;
	

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		
    	//自定义图片处理
    	ImageCodeFilter  imageCodeFilter=new ImageCodeFilter();
    	imageCodeFilter.setMyAuthenticationFailureHandler(myAuthenticationFailureHandler);
		   
		        http
		        .addFilterBefore(imageCodeFilter, UsernamePasswordAuthenticationFilter.class)
		        .formLogin()    //表单登录
		            .loginPage("/authentication/require")   //自定义登陆的页面
		            .loginProcessingUrl("/authentication/form")   //指定登陆action 的 url
		            .successHandler(myAuthenticationSuccessHandler)  //登录成功处理
		            .failureHandler(myAuthenticationFailureHandler)  //登出失败处理
		            .and()
		            .rememberMe()
		            .tokenRepository(persistentTokenRepository())
		            .tokenValiditySeconds(3600)
		            .userDetailsService(myUserDetailsService)
		            .and()
		            .sessionManagement()
		            .invalidSessionUrl("/session/invalid")
		            //并发只允许一个用户
		            .maximumSessions(1)
		            //并发处理策略
		            .expiredSessionStrategy(new MyExpiredSessionStrategy())
				    .and()
				    .and()
				    
				    .logout()
				    .logoutUrl("/logout")
				   // .logoutSuccessUrl("logout.html")
				    .logoutSuccessHandler(myLogoutSuccessHandler)
				    .deleteCookies("JSESSIONID")
				    
				    .and()
				    .authorizeRequests()  //请求认证模块   所有请求都需要认证     
				    .antMatchers("/authentication/require",
				    		"/logout",
				    		"/login",
				    		"/register/*",
				    		"/code/image").permitAll()  //登录页面不认证
					.anyRequest().authenticated()  //所有请求认证
					.and()
					.csrf().disable();  //跨站请求伪造
					
	}


}

从数据库读取用户数据

@Component
public class MyUserDetailsService implements UserDetailsService{

    private static final Logger LOGGER = LoggerFactory.getLogger(MyUserDetailsService.class);
    
    @Autowired
    private PersonDao personDao;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LOGGER.info("表单登录用户名:{}", username);
        //从数据库读取用户
        Person person=personDao.findByUsername(username);
        
        String password=person.getPassword();
          
        LOGGER.info("数据库密码:{}", password);        
        
        return new User(username, 
        		password,
        		true,   //可用
        		true,   //账户过期
        		true,  //认证过期
        		true, //锁定用户
        		AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_USER"));
    }

}

密码加密方式用BCryptPasswordEncoder, 最大的好处是对同一字符串加密, 得到的加密结果不一样.

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {

	@Autowired
	PersonService personService;
	
	@Autowired
	PasswordEncoder passwordEncoder;

	@Test
	public void testAddPerson() {
		Person person =new Person();
		person.setUsername("yue");
		person.setPassword("123456");
		personService.addPerson(person);
	}
	

	@Test
	public void testPasswordEncoder() {
		String password ="123456";
		String encodeStr1 = passwordEncoder.encode(password);
		System.out.println("第一次加密:"+encodeStr1);
		String encodeStr2 = passwordEncoder.encode(password);
		System.out.println("第二次加密:"+encodeStr2);
		System.out.println(passwordEncoder.matches(password, encodeStr2));
		
	}

}


//第一次加密:$2a$10$wNj/Cvd0Bp6XSlsOwEmjb.xAlM.tJ8DxygltLwAYCZ8b.pY6fZ7ga
//第二次加密:$2a$10$x2WnKVuu0DnorqBX7xw/TOKMRWSJypCg/fxihaVUw.4DsPYuAhyoG
//true

四、项目文件结构截图

   image.png

五、启动部署流程

首先 在mysql创建数据库security-demo,  在数据库执行sqlj脚本: security-demo.sql.

image.png

然后eclipse导入maven项目, 待maven依赖jar包加载完成后, 得到目录结构.

image.png

右击DemoApplication --> run as -->Java Application, 启动成功后访问: http://localhost:8080

六、演示效果

登录页面

image.png


账户/密码 admin/123456 , 进入首页:

image.png

注册页:

image.png



本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码