@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