1. 程式人生 > 其它 >實習週記(三):學了一半的spring security,看了一遍的swagger,不太熟悉的定時與郵件

實習週記(三):學了一半的spring security,看了一遍的swagger,不太熟悉的定時與郵件

SpringSecurity

提供了一套Web應用安全性的完整解決方案

使用者認證

驗證某個使用者是否為系統中的合法主體,通俗意義上為系統驗證使用者是否能夠登入

使用者授權

驗證某個使用者是否有許可權執行某個操作,在一個系統中,不同使用者所就有的許可權是不同的

特點

  1. 與spring結合性好
  2. 全面的許可權控制
  3. 專門為web開發而設計
  4. 重量級(需要引入較多的依賴)

Demo

  1. 匯入spring security依賴
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>2.5.3</version>
</dependency>
  1. 編寫controller
@Controller
public class logincontroller {

    @GetMapping("/login")
    public String login() {
        return "login";
    }

正常會跳轉至login頁面,但是添加了spring security後,會跳轉至驗證介面,預設使用者名稱為User,密碼為控制檯隨機生成的密碼

原理

實質上是一個過濾器鏈,重點有三個過濾器

FilterSecurityInterceptor

一個方法級的許可權過濾器,位於過濾鏈的底端,控制方法是否能被訪問

ExceptionTranslationFilter

異常過濾器,用於處理在認證授權過程中丟擲的異常

UsernamePasswordAuthenticationFilter

對/login的post請求進行攔截,校驗表單中的使用者名稱和密碼

載入過程

呼叫doFilter中的初始化方法,獲取FilterChainProxy,並通過FilterChainProxy遍歷載入器,放在集合中返回

介面

UserDetailsService

沒有配置時,賬號密碼是由Spring security自定義生成的,為了滿足業務需求,我們需要自定義邏輯控制認證邏輯

PasswordEncoder

資料加密介面,一般用於密碼加密

Web許可權方案

認證

先查詢配置檔案-->查詢配置類-->查詢實現了UserDetailsService介面的實現類

  1. 通過配置檔案設定

    spring.security.user.name=???
    spring.security.user.password=???
    
  2. 通過配置類實現

    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter{
       @Override
        protected void configure(AuthenticationManageBuilder auth) throws Exception{
             //加密
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode("123");
        auth.inMemoryAuthentication().withUser("chenchenchen").password(password).roles("admin");
        }
        
        //如果不建立此物件,會報錯,找不到對應的物件
        @Bean
        PasswordEncoder password(){
            return new BCryptPasswordEncoder();
        }
    }
    
  3. 自定義實現類

    1. 建立配置類,設定使用哪個userDetailsService實現類
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter{
       @Autowired
        private UserDetailService userDetailService;
       @Override
        protected void configure(AuthenticationManageBuilder auth) throws Exception{
             //加密
            auth.userDetailsService(userDetailsService).passwordEncoder(password());
        }
        
        //如果不建立此物件,會報錯,找不到對應的物件
        @Bean
        PasswordEncoder password(){
            return new BCryptPasswordEncoder();
        }
    }
    
    1. 編寫實現類,返回User物件
    @Service
    public class MyUserDetailsService implements UserDetailsService{
        @Override
        public UserDetails loadUserByUsername(String s) throw UsernameNotFoundException{
            List<GrantedAuthority> auths = 
                AuthorityUtils.commaSeparatedStringToAuthorityList("role");
            return new User("chenchenchen",new BCryptPasswordEncoder().encode("123456"),auths)//auths為角色
        }
    }
    

許可權

  1. 建立配置類
  2. 在配置類中設定攔截內容/在controller上使用註解設定許可權

自動登入

實現

  1. 建立使用者表

    CREATE TABLE `persistent_logins` (
     `username` varchar(64) NOT NULL,
     `series` varchar(64) NOT NULL,
     `token` varchar(64) NOT NULL,
     `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE
    CURRENT_TIMESTAMP,
     PRIMARY KEY (`series`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
  2. 配置類,注入資料來源

    @Configuration
    public class BrowserSecurityConfig {
    @Autowired
    private DataSource dataSource;
    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
     JdbcTokenRepositoryImpl jdbcTokenRepository = new
    JdbcTokenRepositoryImpl();
    // 賦值資料來源
    jdbcTokenRepository.setDataSource(dataSource);
    // 自動建立表,第一次執行會建立,如果表存在則應當刪除
    jdbcTokenRepository.setCreateTableOnStartup(true);
    return jdbcTokenRepository;
     }
    }
    

Swagger

  • 世界上最流行的Api框架
  • 前後端交流的工具
  • 即時生成Api文件
  • 可線上測試介面

Spring Boot整合Swagger

  1. 匯入相應依賴包

    <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
    <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger2</artifactId>
       <version>2.9.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
    <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger-ui</artifactId>
       <version>2.9.2</version>
    </dependency>
    
  2. 編寫配置類

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
    
        @Bean
        public Docket docket(){
            return  new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo())
                    .enable(true)              //是否啟用swagger
                    .groupName("陳晨橙")          //分組,可以設定多個docket
                    .select()
                    .apis(RequestHandlerSelectors.basePackage("com.shaem.swagger.controller"))	//定義掃描的包
                //攔截除了shaem以外的介面
                    .paths(PathSelectors.ant("/shaem/**"))
                    .build();
        }
    
    
        public ApiInfo apiInfo(){
            return new ApiInfoBuilder()
                    .title("陳晨橙")
                    .description("test")
                    .version("1.0")
                    .termsOfServiceUrl("Url")
                    .contact(new Contact("name","url","email"))
                    .build();
        }
    }
    
    
  3. 重啟專案,訪問測試 http://localhost:8080/swagger-ui.html

配置API分組

  1. 預設為default,通過groupName()可以配置分組
  2. 可以通過配置多個Docket達到分組效果
@Bean
public Docket docket1(){
   return new Docket(DocumentationType.SWAGGER_2).groupName("group1");
}
@Bean
public Docket docket2(){
   return new Docket(DocumentationType.SWAGGER_2).groupName("group2");
}
@Bean
public Docket docket3(){
   return new Docket(DocumentationType.SWAGGER_2).groupName("group3");
}

實體類配置

  1. 使用ApiModel標識實體類
  2. 使用ApiModelProperty標識屬性
  3. 只要請求介面返回值存在實體類,即會出現在文件中
@ApiModel("使用者實體")
public class User {
   @ApiModelProperty("使用者名稱")
   public String username;
   @ApiModelProperty("密碼")
   public String password;
}
@RequestMapping("/getUser")
public User getUser(){
   return new User();
}

常用註解

下面列一些經常用到的,未列舉出來的可以另行查閱說明:

Swagger註解 簡單說明
@Api(tags = "xxx模組說明") 作用在模組類上
@ApiOperation("xxx介面說明") 作用在介面方法上
@ApiModel("xxxPOJO說明") 作用在模型類上:如VO、BO
@ApiModelProperty(value = "xxx屬性說明",hidden = true) 作用在類方法和屬性上,hidden設定為true可以隱藏該屬性
@ApiParam("xxx引數說明") 作用在引數、方法和欄位上,類似@ApiModelProperty

定時、非同步與郵件

定時

spring提供兩個介面讓我們能實現定時執行任務的功能

  • Task Executor介面
  • Task Scheduler介面

在微服務中,我們通常使用註解來實現

  • @EnableScheduling(新增在啟動類上)
  • @Scheduled(cron=“表示式”) //新增在想要執行的方法上

cron表示式

  一、結構

  corn從左到右(用空格隔開):秒 分 小時 月份中的日期 月份 星期中的日期 年份

  二、各欄位的含義

欄位 允許值 允許的特殊字元
秒(Seconds) 0~59的整數 , - * / 四個字元
分(Minutes 0~59的整數 , - * / 四個字元
小時(Hours 0~23的整數 , - * / 四個字元
日期(DayofMonth 1~31的整數(但是你需要考慮你月的天數) ,- * ? / L W C 八個字元
月份(Month 1~12的整數或者 JAN-DEC , - * / 四個字元
星期(DayofWeek 1~7的整數或者 SUN-SAT (1=SUN) , - * ? / L C # 八個字元
年(可選,留空)(Year 1970~2099 , - * / 四個字元

 注意事項:

  每一個域都使用數字,但還可以出現如下特殊字元,它們的含義是:

  (1)✳:表示匹配該域的任意值。假如在Minutes域使用*, 即表示每分鐘都會觸發事件。

  (2)?:只能用在DayofMonth和DayofWeek兩個域。它也匹配域的任意值,但實際不會。因為DayofMonth和DayofWeek會相互影響。例如想在每月的20日觸發排程,不管20日到底是星期幾,則只能使用如下寫法: 13 13 15 20 * ?, 其中最後一位只能用?,而不能使用,如果使用表示不管星期幾都會觸發,實際上並不是這樣。

  (3)-:表示範圍。例如在Minutes域使用5-20,表示從5分到20分鐘每分鐘觸發一次

  (4)/:表示起始時間開始觸發,然後每隔固定時間觸發一次。例如在Minutes域使用5/20,則意味著5分鐘觸發一次,而25,45等分別觸發一次.

  (5),:表示列出列舉值。例如:在Minutes域使用5,20,則意味著在5和20分每分鐘觸發一次。

  (6)L:表示最後,只能出現在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味著在最後的一個星期四觸發。

  (7)W:表示有效工作日(週一到週五),只能出現在DayofMonth域,系統將在離指定日期的最近的有效工作日觸發事件。例如:在 DayofMonth使用5W,如果5日是星期六,則將在最近的工作日:星期五,即4日觸發。如果5日是星期天,則在6日(週一)觸發;如果5日在星期一到星期五中的一天,則就在5日觸發。另外一點,W的最近尋找不會跨過月份 。

  (8)LW:這兩個字元可以連用,表示在某個月最後一個工作日,即最後一個星期五。

  (9)#:用於確定每個月第幾個星期幾,只能出現在DayofMonth域。例如在4#2,表示某月的第二個星期三。

非同步

傳送郵件一般不能立刻傳送,讓使用者等待會降低體驗,這個時候就可以用非同步來模擬同步效果,讓後臺執行傳送郵件的功能,其中涉及到多執行緒

  1. 在啟動類上新增@EnableAsync
  2. 在方法上使用@Async
  3. 測試

郵件

在spring boot中使用郵件服務

  1. 引入依賴

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    
  2. 配置檔案

    [email protected]
    #授權碼可以在郵箱中的賬號中找到
    spring.mail.password=qq授權碼 
    spring.mail.host=smtp.qq.com
    # qq需要配置ssl
    spring.mail.properties.mail.smtp.ssl.enable=true
    
  3. 測試

     SimpleMailMessage message = new SimpleMailMessage();
       message.setSubject("通知-今晚早點下班");
       message.setText("今晚7:00下班");
    
       message.setTo("[email protected]");
       message.setFrom("[email protected]");
       mailSender.send(message);
    
     MimeMessage mimeMessage = mailSender.createMimeMessage();
       MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
    
       helper.setSubject("通知");
       helper.setText("<b style='color:red'>今天 6:30下班</b>",true);
    
       //傳送附件
       helper.addAttachment("1.jpg",new File(""));
       helper.addAttachment("2.jpg",new File(""));
    
       helper.setTo("[email protected]");
       helper.setFrom("[email protected]");
    
       mailSender.send(mimeMessage);