1. 程式人生 > >CAS 5.1.X版本自定義jdbc驗證

CAS 5.1.X版本自定義jdbc驗證

一、前言

在不同的專案中,可能由於業務需求或者架構方式的不同,對於使用者登入的驗證方式也不同。CAS為我們提供了很多的認證模式,其中最常見的認證方式有:

  • JDBC認證,可以通過配置,也可以重寫cas相關方法進行自定義認證
  • LDAP認證
  • Basic認證
  • Shrio認證
  • Pac4j認證
  • MongoDB認證
  • Rest認證
  • IP黑白名單
  • 第三方認證:微信,QQ,github等

在筆者最近接手的專案中,考慮後期驗證方式的變化和程式的擴充套件性,決定重寫CAS的驗證方法進行自定義驗證。另外,對於登入的驗證資訊,我們除了使用者名稱和密碼,可能還需要部門資訊,驗證碼等等,這也需要重寫cas的方法。

二、實戰

2.1 pom檔案

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion
>
<groupId>com.simon.cas</groupId> <artifactId>cas_boot</artifactId> <version>2.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>cas_boot</name> <description>cas服務端</description> <properties>
<cas.version>5.1.5</cas.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <springboot.version>2.0.2.RELEASE</springboot.version> <spring-cloud.version>Finchley.SR1</spring-cloud.version> <java.version>1.8</java.version> </properties> <dependencies> <!--cas--> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-webapp-tomcat</artifactId> <version>${cas.version}</version> <!--這裡必須新增type war--> <type>war</type> <scope>runtime</scope> </dependency> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-configuration</artifactId> <version>${cas.version}</version> </dependency> <!--新增支援服務註冊--> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-eureka-client</artifactId> <version>${cas.version}</version> </dependency> <!--新增支援jdbc驗證--> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-jdbc</artifactId> <version>${cas.version}</version> </dependency> <!-- 若不想找驅動可以直接寫下面的依賴即可,其中包括HSQLDB、Oracle、MYSQL、PostgreSQL、MariaDB、Microsoft SQL Server --> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-jdbc-drivers</artifactId> <version>${cas.version}</version> </dependency> <!--自定義認證,重寫Credential--> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-core-webflow</artifactId> <version>${cas.version}</version> </dependency> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-webapp-config</artifactId> <version>${cas.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-validation</artifactId> <version>${cas.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <scope>provided</scope> <version>3.1.0</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-bom</artifactId> <version>${cas.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>com.rimerosolutions.maven.plugins</groupId> <artifactId>wrapper-maven-plugin</artifactId> <version>0.0.4</version> <configuration> <verifyDownload>true</verifyDownload> <checksumAlgorithm>MD5</checksumAlgorithm> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${springboot.version}</version> <configuration> <mainClass>org.springframework.boot.loader.WarLauncher</mainClass> <addResources>true</addResources> <executable>false</executable> <layout>WAR</layout> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.1.0</version> <configuration> <warName>cas</warName> <failOnMissingWebXml>false</failOnMissingWebXml> <recompressZippedFiles>false</recompressZippedFiles> <archive> <compress>false</compress> <manifestFile>${project.build.directory}/war/work/org.apereo.cas/cas-server-webapp-tomcat/META-INF/MANIFEST.MF</manifestFile> </archive> <overlays> <overlay> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-webapp-tomcat</artifactId> </overlay> </overlays> <!-- <dependentWarExcludes> --> <!--&lt;!&ndash;war包下的服務不進行初始化&ndash;&gt;--> <!--**/services/*.json--> <!--</dependentWarExcludes>--> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> </plugin> </plugins> <finalName>cas</finalName> </build> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>sonatype-releases</id> <name>sonatype-releases</name> <url>https://oss.sonatype.org/content/repositories/releases/</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>sonatype-snapshots</id> <name>sonatype-snapshots</name> <url>http://oss.sonatype.org/content/repositories/snapshots/</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>shibboleth-releases</id> <name>shibboleth-releases</name> <url>https://build.shibboleth.net/nexus/content/repositories/releases</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>jasig-dev-legacy</id> <name>jasig-dev-legacy</name> <url>http://developer.jasig.org/repo/content/groups/m2-legacy</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>duo-uniconiam</id> <name>duo-uniconiam</name> <url>https://dl.bintray.com/uniconiam/maven</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>jitpack</id> <name>jitack</name> <url>https://jitpack.io</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project>

2.2 配置檔案

服務的配置檔案統一使用Spring Cloud config配置中心進行管理。

bootstrap.properties

#日誌目錄
logging.file=logs/cas.log
#服務名
spring.application.name=cas
#從配置中心獲取cas-dev.properties配置
spring.profiles.active=dev
#分支
#spring.cloud.config.label=master

#註冊中心
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka-server/eureka
#通過服務名獲取配置中心
#spring.cloud.config.discovery.enabled=true
#spring.cloud.config.discovery.serviceId=config-server
#spring.cloud.config.failFast=true
spring.cloud.config.uri = http://localhost:8080/config-server
#獲取配置失敗快速響應
spring.cloud.config.failFast=true

cas-dev.properties

##
# CAS服務上下文配置
#
#訪問路徑
server.context-path=/cas
#訪問埠
server.port=8080

#關閉ssl
server.ssl.enabled=false
#設定持有SSL certificate的key store的路徑
#server.ssl.key-store=classpath:tomcat.keystore
#設定訪問key store的密碼
#server.ssl.key-store-password=123456
#server.ssl.keyAlias=passport.sso.com
# server.ssl.ciphers=
# server.ssl.client-auth=

# server.ssl.key-alias=
# server.ssl.key-store-provider=
# server.ssl.key-store-type=
# server.ssl.protocol=
# server.ssl.trust-store=
# server.ssl.trust-store-password=
# server.ssl.trust-store-provider=
# server.ssl.trust-store-type=

#解決http下登入狀態不互通
cas.tgc.secure=false
cas.warningCookie.secure=false

#允許發出退出控制退出後轉發url
cas.logout.followServiceRedirects=true


server.max-http-header-size=2097152
server.use-forward-headers=true
server.connection-timeout=20000
server.error.include-stacktrace=NEVER
#設定http header的最小值,預設: 0
server.tomcat.max-http-post-size=2097152
#設定Tomcat的base 目錄,如果沒有指定則使用臨時目錄
server.tomcat.basedir=build/tomcat
#是否開啟access log,預設: false
server.tomcat.accesslog.enabled=true
#設定access logs的格式,預設: common
server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
#設定Log 檔案的字首,預設: access_log
server.tomcat.accesslog.suffix=.log
#設定tomcat的最大工作執行緒數,預設為: 0
server.tomcat.max-threads=10
#設定http header使用的,用來覆蓋原來port的value
server.tomcat.port-header=X-Forwarded-Port
#設定Header包含的協議,通常是 X-Forwarded-Proto,如果remoteIpHeader有值,則將設定為RemoteIpValve.
server.tomcat.protocol-header=X-Forwarded-Proto
#設定使用SSL的header的值,預設https.
server.tomcat.protocol-header-https-value=https
#設定remote IP的header,如果remoteIpHeader有值,則設定為RemoteIpValve
server.tomcat.remote-ip-header=X-FORWARDED-FOR
#設定URI的解碼字符集.
server.tomcat.uri-encoding=UTF-8

spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
##########################################################JDBC驗證##############################################################################
###
## Query Database Authentication 資料庫查詢校驗使用者名稱開始
##
##查詢賬號密碼sql,必須包含密碼欄位,根據sql給予使用者名稱進行查詢根據密碼欄位進行鑑定
#cas.authn.jdbc.query[0].sql=select * from sys_user where username=?
##指定上面的sql查詢欄位名(必須)
#cas.authn.jdbc.query[0].fieldPassword=password
##指定過期欄位,1為過期,若過期不可用
#cas.authn.jdbc.query[0].fieldExpired=expired
##為不可用欄位,1為不可用,需要修改密碼
#cas.authn.jdbc.query[0].fieldDisabled=disabled
##資料庫方言hibernate的知識
#cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.HSQLDialect
##資料庫驅動
#cas.authn.jdbc.query[0].driverClass=org.hsqldb.jdbcDriver
##資料庫連線
#cas.authn.jdbc.query[0].url=jdbc:hsqldb:mem:cas-hsql-database
##資料庫使用者名稱
#cas.authn.jdbc.query[0].user=sa
##資料庫密碼
#cas.authn.jdbc.query[0].password=
##預設加密策略,通過encodingAlgorithm來指定演算法,預設NONE不加密
#cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT
#cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
#cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5
#Query Database Authentication 資料庫查詢校驗使用者名稱結束

##
#Encode Database Authentication 編碼加密開始
#   對密碼進行鹽值處理再加密,增加了反查難度
#
#加密次數
#cas.authn.jdbc.encode[0].numberOfIterations=2
#該列名的值可替代上面的值,但對密碼加密時必須取該值進行處理
#cas.authn.jdbc.encode[0].numberOfIterationsFieldName=
# 鹽值固定列
#cas.authn.jdbc.encode[0].saltFieldName=username
#靜態鹽值
#cas.authn.jdbc.encode[0].staticSalt=.
#cas.authn.jdbc.encode[0].sql=select * from sys_user_encode where username=?
#對處理鹽值後的演算法
#cas.authn.jdbc.encode[0].algorithmName=MD5
#cas.authn.jdbc.encode[0].passwordFieldName=password
#cas.authn.jdbc.encode[0].expiredFieldName=expired
#cas.authn.jdbc.encode[0].disabledFieldName=disabled
#cas.authn.jdbc.encode[0].url=jdbc:hsqldb:mem:cas-hsql-database
#cas.authn.jdbc.encode[0].dialect=org.hibernate.dialect.HSQLDialect
#cas.authn.jdbc.encode[0].user=sa
#cas.authn.jdbc.encode[0].password=
#cas.authn.jdbc.encode[0].driverClass=org.hsqldb.jdbcDriver
#Encode Database Authentication 編碼加密結束

##########################################################Shrio驗證##############################################################################
# Shiro Authentication 開始
#允許登入的使用者,必須要有以下許可權,否則拒絕,多個逗號隔開
#cas.authn.shiro.requiredPermissions=staff
#允許登入的使用者,必須要有以下許可權,否則拒絕,多個逗號隔開
#cas.authn.shiro.requiredRoles=admin
#shiro配置檔案位置
#cas.authn.shiro.config.location=classpath:shiro.ini
#shiro name 唯一
#cas.authn.shiro.name=cas-shiro
# 與Query Authentication一致的加密策略
#cas.authn.shiro.passwordEncoder.type=DEFAULT
# 使用MD5加密
#cas.authn.shiro.passwordEncoder.encodingAlgorithm=MD5
# Shiro Authentication 結束

##########################################################REST 認證##############################################################################
#REST 認證開始
#請求遠端呼叫介面
#cas.authn.rest.uri=http://localhost:8101/login
#加密策略
#cas.authn.rest.passwordEncoder.type=DEFAULT
#cas.authn.rest.passwordEncoder.characterEncoding=UTF-8
#加密演算法
#cas.authn.rest.passwordEncoder.encodingAlgorithm=MD5
#REST 結束

#設定預設主題 cas5.1.0-cas5.1.6版本無法使用預設主題,需要覆蓋
#cas.theme.defaultThemeName=100000

##
# CAS Cloud Bus Configuration
#
spring.cloud.bus.enabled=false
# spring.cloud.bus.refresh.enabled=true
# spring.cloud.bus.env.enabled=true
# spring.cloud.bus.destination=CasCloudBus
# spring.cloud.bus.ack.enabled=true

endpoints.enabled=false
endpoints.sensitive=true

endpoints.restart.enabled=false
endpoints.shutdown.enabled=false

management.security.enabled=true
management.security.roles=ACTUATOR,ADMIN
management.security.sessions=if_required
management.context-path=/status
management.add-application-context-header=false

security.basic.authorize-mode=role
security.basic.enabled=false
security.basic.path=/cas/status/**

##
# CAS Web Application Session Configuration
#
server.session.timeout=300
server.session.cookie.http-only=true
server.session.tracking-modes=COOKIE

##
# CAS Thymeleaf View Configuration
#
spring.thymeleaf.encoding=UTF-8
#禁止頁面緩衝
spring.thymeleaf.cache=false
spring.thymeleaf.mode=HTML
#預設是.html
#spring.thymeleaf.suffix=.jsp

##
# CAS Log4j Configuration
#
# logging.config=file:/etc/cas/log4j2.xml
server.context-parameters.isLog4jAutoInitializationDisabled=true

##
# CAS AspectJ Configuration
#
spring.aop.auto=true
spring.aop.proxy-target-class=true

##
# CAS Authentication Credentials
#
#cas.authn.accept.users=casuser::Mellon
#不容許靜態使用者
staticAuthentication=false

#開啟識別json檔案,預設false
cas.serviceRegistry.initFromJson=true

#下面所是資料來源,讓spring boot自動配置,預設cas遮蔽了spring boot自動配置,下面的程式碼中我們在spring boot掃描的目錄中開啟這個配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.10.58:3306/bdc_job?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=Ibase2016
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource

spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

#連線池配置
##初始化連線:連線池啟動時建立的初始化連線數量
spring.datasource.dbcp2.initial-size=5
#最大活動連線:連線池在同一時間能夠分配的最大活動連線的數量, 如果設定為非正數則表示不限制
spring.datasource.dbcp2.max-active=1000
#最大空閒連線:連線池中容許保持空閒狀態的最大連線數量,超過的空閒連線將被釋放,如果設定為負數表示不限制
spring.datasource.dbcp2.max-idle=100
#從連線池獲取一個連線時,最大的等待時間,設定為-1時,如果沒有可用連線,連線池會一直無限期等待,直到獲取到連線為止。
#如果設定為N(毫秒),則連線池會等待N毫秒,等待不到,則丟擲異常
spring.datasource.dbcp2.max-wait-millis=60000
#通過這個池建立連線的預設自動提交狀態。如果不設定,則setAutoCommit 方法將不被呼叫
spring.datasource.dbcp2.default-auto-commit=true
#通過這個池建立連線的預設只讀狀態。如果不設定,則setReadOnly  方法將不被呼叫。(部分驅動不支援只讀模式,如:Informix)
spring.datasource.dbcp2.default-read-only=false
#指明在從池中租借物件時是否要進行驗證有效,如果物件驗證失敗,則物件將從池子釋放,然後我們將嘗試租借另一個
spring.datasource.dbcp2.test-on-borrow=true

#自定義屬性 這些屬性我們在jdbc驗證的時候需要
#使用者名稱,密碼查詢
user.password.query.sql = select u.USERID,u.DEVICESTRING as DEVICE_,u.UKEYSTRING as UKEY_ from USERINFO u left join ORGANINFO o on u.USERID=o.RID where u.LOGINNAME = ? and u.USERPASSWORD = ?
#ukey查詢
user.ukey.query.sql = select u.USERID from USERINFO u left join ORGANINFO o on u.USERID=o.RID where u.UKEYSTRING = ?
#系統配置查詢(通過系統配置服務獲取自定義介面的一些配置資訊的sql語句)
syscfg.query.sql = select SVALUE from SYSKEY where CCATALOG = ? and SKEY = ?

2.3 擴充套件登入資訊

cas預設提供的登入資訊往往不能滿足我們的需求,在這裡我們將增加系統名,驗證碼作為登入的擴充套件資訊

繼承RememberMeUsernamePasswordCredential擴充套件登入資訊

public class UsernamePasswordSubSystemCredential extends RememberMeUsernamePasswordCredential {

  /**
   * 驗證碼
   */
  private String captcha;

  /**
   * 子系統
   */
  private String system;

  /**
   * 獲取驗證碼
   *
   * @return
   *        驗證碼
   */
  public String getCaptcha() {
    return captcha;
  }

  /**
   * 設定驗證碼
   *
   * @param captcha
   *        驗證碼
   */
  public void setCaptcha(String captcha) {
    this.captcha = captcha;
  }

  /**
   * 獲取子系統
   *
   * @return
   *        子系統
   */
  public String getSystem() {
    return system;
  }

  /**
   * 設定子系統
   *
   * @param system
   *        子系統
   */
  public void setSystem(String system) {
    this.system = system;
  }


  /**
   * 計算hash碼.
   *
   * 根據規範,一旦重寫{@code equals()}就必須重寫此{@code hashCode()}方法。
   */
  @Override
  public int hashCode() {
    return new HashCodeBuilder().appendSuper(super.hashCode()).append(this.system).append(this.getCaptcha()).toHashCode();
  }
}

將擴充套件的登入資訊繫結到登入的webflow流程中

public class CustomWebflowConfigurer extends AbstractCasWebflowConfigurer {
  /**
   * 注入系統配置查詢bean
   */
  @Autowired
  private SysConfigQueryService sysConfigQueryService;

  /**
   * 建構函式
   *
   * @param flowBuilderServices
   * @param loginFlowDefinitionRegistry
   */
  public CustomWebflowConfigurer(FlowBuilderServices flowBuilderServices, FlowDefinitionRegistry loginFlowDefinitionRegistry) {
    super(flowBuilderServices, loginFlowDefinitionRegistry);
  }

  @Override
  protected void doInitialize() throws Exception {
    Flow flow = getLoginFlow();
    bindCredential(flow);
  }

  /**
   * 繫結輸入資訊
   *
   * @param flow
   *          流程
   */
  protected void bindCredential(Flow flow){
    //重寫繫結自定義credential
    createFlowVariable(flow,CasWebflowConstants.VAR_ID_CREDENTIAL,UsernamePasswordSubSystemCredential.class);
    //登入頁繫結新引數
    final ViewState state = (ViewState)flow.getState(CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM);

    final BinderConfiguration cfg = getViewStateBinderConfiguration(state);
    //由於使用者名稱以及密碼已經繫結,所以只需對新加系統引數繫結即可
    //引數1 :欄位名
    //引數2 :轉換器
    //引數3 :是否必須的欄位
    cfg.addBinding(new BinderConfiguration.Binding("system", null, false));
    cfg.addBinding(new BinderConfiguration.Binding("captcha",null,false));

    //進入viewstate前傳入引數(在系統引數繫結之後設定)
    ActionList entryActionList = state.getEntryActionList();
    entryActionList.add(createEvaluateAction("viewScope.newReg="+sysConfigQueryService.getNewRegister()));
    entryActionList.add(createEvaluateAction("viewScope.pwdReset="+sysConfigQueryService.getResetPassword()));
    entryActionList.add(createEvaluateAction("viewScope.codeValidate="+sysConfigQueryService.getImageValidate()));
    //系統名稱
    entryActionList.add(createEvaluateAction("viewScope.sysTitle="+sysConfigQueryService.getSysTitle()));
  }
}

在上面的程式碼中,我們除了繫結新新增的登入資訊,還設定entryActionList(這個是Spring webflow的一個自定義切點,表示進入某個 state 之後,做其他事情之前,執行相關業務邏輯。Spring Web Flow 共定義了5個切入點,具體可以檢視https://docs.spring.io/spring-webflow/docs/2.5.0.RELEASE/reference/html/el.html#el-variable-viewScope ),這樣在頁面上可以通過${newReg},${pwdReset}...獲取傳入的相關資訊來進行有一些邏輯操作。需要注意的是上面程式碼繫結新登入資訊和設定entryActionList的順序不能改變,否則在驗證的時候無法獲取新增的登入資訊。另外,SysConfigQueryService的程式碼也不貼出來了,這裡主要就是通過jdbcTemplate查詢系統配置資訊。

註冊修改後的登入流程

@Configuration("customerAuthWebflowConfiguration")
@EnableConfigurationProperties(value = CasConfigurationProperties.class)
@AutoConfigureBefore(value = CasWebflowContextConfiguration.class)
public class CustomerAuthWebflowConfiguration {

  @Autowired
  @Qualifier("logoutFlowRegistry")
  private FlowDefinitionRegistry logoutFlowRegitry;

  @Autowired
  @Qualifier("loginFlowRegistry")
  private FlowDefinitionRegistry loginFlowRegistry;

  @Autowired
  @Qualifier("builder")
  private FlowBuilderServices builder;

  @Bean
  public CasWebflowConfigurer customWebflowConfigurer() {
    final CustomWebflowConfigurer customWebflowConfigurer = new CustomWebflowConfigurer(builder, loginFlowRegistry);
    customWebflowConfigurer.setLogoutFlowDefinitionRegistry(logoutFlowRegitry);
    return customWebflowConfigurer;
  }
}

2.4 自定義驗證

這裡我們使用jdbc進行驗證,通過使用者登入資訊使用jdbcTemplate進行查詢。

繼承AbstractPreAndPostProcessingAuthenticationHandler進行自定義認證

public class UsernamePasswordSystemAuthenticationHandler extends AbstractPreAndPostProcessingAuthenticationHandler {

  /**
   * 為了符合cacheService key的名稱定義格式。
   */
  public static final String CSUFFIX_USERLOGIN = "_2ae941e8-21e5-4013-9568-4dcee975333a";

  /**
   * 根據使用者名稱和密碼查詢sql語句
   */
  @Value("${user.password.query.sql}")
  private String userQuerySql;

  /**
   * 根據ukey查詢sql語句
   */
  @Value("${user.ukey.query.sql}")
  private String uKeyQuerySql;

  /**
   * jdbc模板
   */
  @Autowired
  private JdbcTemplate jdbcTemplate;

  /**
   * 建構函式
   *
   * @param name
   * @param servicesManager
   * @param principalFactory
   * @param order
   */
  public UsernamePasswordSystemAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) {
    super(name, servicesManager, principalFactory, order);
  }


  @Override
  protected HandlerResult doAuthentication(Credential credential) throws GeneralSecurityException, PreventedException {
    final UsernamePasswordSubSystemCredential upssc = (UsernamePasswordSubSystemCredential) credential;
    final String username = upssc.getUsername();
    //這裡我省略了jdbc驗證程式碼,大家可以自己去實現
    if(username.equals("admin")){
      return createHandlerResult(upssc, this.principalFactory.createPrincipal(upssc.getUsername(),Collections.emptyMap()), null);
    }
    return null;
  }

  @Override
  public boolean supports(Credential credential) {
    return credential instanceof UsernamePasswordSubSystemCredential;
  }
}

註冊自定義驗證器

@Import({DataSourceAutoConfiguration.class})
@Configuration("customAuthenticationEventExecutionPlanConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CustomAuthenticationEventExecutionPlanConfiguration implements AuthenticationEventExecutionPlanConfigurer {
  @Autowired
  @Qualifier("servicesManager")
  private ServicesManager servicesManager;

  @Autowired
  @Qualifier("jdbcPrincipalFactory")
  public PrincipalFactory jdbcPrincipalFactory;


  /**
   * 註冊驗證器
   *
   * @return
   */
  @Bean
  public AuthenticationHandler customAuthenticationHandler() {
    //優先驗證
    return new UsernamePasswordSystemAuthenticationHandler
            ("customAuthenticationHandler", servicesManager,new DefaultPrincipalFactory(),1);
  }

  //註冊自定義認證器
  @Override
  public void configureAuthenticationExecutionPlan(final AuthenticationEventExecutionPlan plan) {
    plan.registerAuthenticationHandler(customAuthenticationHandler());
  }
}

我們在程式碼中增加了@Import({DataSourceAutoConfiguration.class}),開啟Spring Boot資料來源自動配置,這樣才可以使用使用jdbcTemplate。為什麼在這裡配置的,因為我會將個類配置在Spring B