@css
Spring Security 是 Spring 家族中的一个安全管理框架,应用程序的两个主要区域是“认证”和“受权”(或者访问控制)。Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型html
这两个主要区域是Spring Security 的两个目标。html5
环境准备:java
建立一个SpringBoot Initialize项目,详情能够参考我以前博客:SpringBoot系列之快速建立项目教程git
新建项目后,检查一下spring-boot-starter-security场景启动器是否配置成功,不须要写版本github
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
SpringBoot有版本仲裁机制,SpringBoot2.2.1的spring-boot-starter-security依赖的Spring security版本是5.2.1的
web
配置Spring Security日志级别,默认是info的,能够修改成debugspring
## logback配置 logging: level: org: springframework: security: info
随便写个接口,访问时候,就会跳到以下图的登陆页面,为何?咱们只是引入maven配置而已,而后帐号密码是什么?其实这个是Spring Security的默认登陆页面,页面代码是在jar包里的,默认的username是user,密码是随机生成的uuid格式的密码
密码会在控制台打印,根据线索,找到自动配置类
要修改默认密码,能够新建application.yml配置文件,加上以下配置数据库
## spring security配置 spring: security: user: name: nicky password: 123
也能够新建Spring Security配置类,注意Spring Security5.2.1版本,配置密码要用BCryptPasswordEncoder加密,不过登陆仍是明文,Spring Security不一样版本各有差异,详情配置仍是参考官方文档bootstrap
@Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //auth.inMemoryAuthentication() auth.inMemoryAuthentication() .withUser("nicky") .password(bcryptPasswordEncoder().encode("123")) .roles("admin"); } @Bean public PasswordEncoder bcryptPasswordEncoder() { return new BCryptPasswordEncoder(); } }
加密方式 | security 4 | security 5 |
---|---|---|
bcrypt | password | {bcrypt}password |
ldap | password | {ldap}password |
MD4 | password | {MD4}password |
MD5 | password | {MD5}password |
noop | password | {noop}password |
pbkdf2 | password | {pbkdf2}password |
scrypt | password | {scrypt}password |
SHA-1 | password | {SHA-1}password |
SHA-256 | password | {SHA-256}password |
sha256 | password | {sha256}password |
拓展:若是要数据库方式校验用户名密码,能够自定义UserDetailsService方式:
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(new CustomPasswordEncoder()); auth.parentAuthenticationManager(authenticationManagerBean()); }
UserDetailsServiceImpl.java
package com.example.springboot.oauth2.service; import com.example.springboot.oauth2.entity.User; import com.example.springboot.oauth2.mapper.UserMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.Arrays; import java.util.List; /** * <pre> * * </pre> * * <pre> * @author mazq * 修改记录 * 修改后版本: 修改人: 修改日期: 2020/04/30 15:15 修改内容: * </pre> */ @Slf4j @Service("userService") public class UserDetailsServiceImpl implements UserDetailsService { @Autowired UserMapper userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if(user == null){ log.info("登陆用户[{}]没注册!",username); throw new UsernameNotFoundException("登陆用户["+username + "]没注册!"); } return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), getAuthority()); } private List getAuthority() { return Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN")); // return Arrays.asList(Collections.emptyList()); } }
@Override protected void configure(HttpSecurity http) throws Exception { http // 配置登陆页并容许访问 .formLogin().usernameParameter("username").passwordParameter("password").loginPage("/login").permitAll() // 配置Basic登陆 //.and().httpBasic() // 配置登出页面 .and().logout().logoutUrl("/logout").logoutSuccessUrl("/") // 开放接口访问权限,不须要登陆受权就能够访问 .and().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll() // api接口须要admin管理员才能访问 .antMatchers("/api/**").hasRole("admin") // 其他全部请求所有须要鉴权认证 .anyRequest().authenticated() // 关闭跨域保护; .and().csrf().disable(); }
配置文件,加上配置
@Override public void configure(WebSecurity web) throws Exception { //解决静态资源被拦截的问题 web.ignoring().antMatchers("/asserts/**"); web.ignoring().antMatchers("/favicon.ico"); }
引入Thymeleaf模板引擎:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
关闭Thymeleaf模板引擎缓存,方便F9自动编译
spring: thymeleaf: cache: false
写个login接口,注意必定要GET方式,POST方式是Spring Security默认的校验接口,接口名称也是/login
@Controller public class LoginController { @GetMapping(value = {"/login"}) public ModelAndView toLogin() { return new ModelAndView("login"); } }
自定义登陆页面,要用post方式,除非你本身写个校验接口,POST /login是Spring Security官方的校验接口,默认用户名参数为username,密码参数为password:
<!DOCTYPE html> <html lang="zh" xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <meta name="description" content="" /> <meta name="author" content="" /> <title>Signin Template for Bootstrap</title> <!-- Bootstrap core CSS --> <link href="../static/asserts/css/bootstrap.min.css" th:href="@{asserts/css/bootstrap.min.css}" rel="stylesheet" /> <!-- Custom styles for this template --> <link href="../static/asserts/css/signin.css" th:href="@{asserts/css/signin.css}" rel="stylesheet"/> </head> <body class="text-center"> <form class="form-signin" th:action="@{/login}" method="post"> <img class="mb-4" th:src="@{asserts/img/bootstrap-solid.svg}" alt="" width="72" height="72" /> <h1 class="h3 mb-3 font-weight-normal" >Oauth2.0 Login</h1> <label class="sr-only" >Username</label> <input type="text" class="form-control" name="username" required="" autofocus="" value="nicky" /> <label class="sr-only" >Password</label> <input type="password" class="form-control" name="password" required="" value="123" /> <div class="checkbox mb-3"> <label> <input type="checkbox" value="remember-me" /> remember me </label> </div> <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button> <p class="mt-5 mb-3 text-muted">© 2019</p> </form> </body> </html>
修改配置文件,.loginPage("/login")
指定自定义的登陆页面
@Override protected void configure(HttpSecurity http) throws Exception { http // 配置登陆页并容许访问 .formLogin().usernameParameter("username").passwordParameter("password").loginPage("/login").permitAll() // 配置Basic登陆 //.and().httpBasic() // 配置登出页面 .and().logout().logoutUrl("/logout").logoutSuccessUrl("/") // 开放接口访问权限,不须要登陆受权就能够访问 .and().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll() // api接口须要admin管理员才能访问 .antMatchers("/api/**").hasRole("admin") // 其他全部请求所有须要鉴权认证 .anyRequest().authenticated() // 关闭跨域保护; .and().csrf().disable(); }
开启记住我功能,登录成功之后,将cookie发给浏览器保存,之后访问页面带上这个cookie,只要经过检查就能够免登陆
@Override protected void configure(HttpSecurity http) throws Exception { //开启记住我功能,登录成功之后,将cookie发给浏览器保存,之后访问页面带上这个cookie,只要经过检查就能够免登陆 http.rememberMe().rememberMeParameter("remeber"); }
ok,Spring Security的知识点比较多,详情请参考官方文档,本博客参考官方文档,作了简单记录,仅仅做为入门参考手册
代码例子下载:code download