catalogue
1. Configuring mysql for cas server
2. cas server custom password encryption method
3. The cas server can customize the theme, that is, the login page, or other pages
4. The cas server adds fields to the form submitted during login
5. cas server custom login verification
6. cas server custom return exception
7. The cas server uses ajax to log in
Environmental Science:
CAS version: 5.3
Download link: git address is: https://github.com/apereo/cas-overlay-template
tomcat: 8
jdk: 1.8
1. First copy the source code of the cas server as follows:
1) Open with idea
In the red box is the code compiled after tomcat is configured through idea.
2) create the src directory as follows, and put the target/cas/META-INF file, target/cas/services and target / CAS / application Properties, copy these three files to resources.
Since CAS supports https by default, if you want to change to support http and obtain some basic configurations of other CAS servers, you can see this article: SSO single sign on (I) create cas server I'm a CSDN blog in mixed IT circle _casserver
1. Configuring mysql for cas server
1,pom.xml
<!--Database authentication related start--> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-jdbc</artifactId> <version>${cas.version}</version> </dependency> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-jdbc-drivers</artifactId> <version>${cas.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!--Database authentication related end-->
2,application.properties configuration file
1) Add a link to mysql
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver cas.authn.jdbc.query[0].url=jdbc:mysql://127.0.0.1:3306/shiro?useUnicode=true&characterEncoding=utf-8 cas.authn.jdbc.query[0].user=root #Database account cas.authn.jdbc.query[0].password=123456 #Database password cas.authn.jdbc.query[0].sql=select password from system_admin_user where account = ? #Table query sql cas.authn.jdbc.query[0].fieldPassword=password #Fields in the table that belong to passwords
2) Comment out the default account password of cas, otherwise the account password can also be logged in
#cas.authn.accept.users=casuser::Mellon
Note: mysql is used for login here, and the password is not encrypted. For example, if the login password is 123456, the password of the database is 123456.
2. cas server custom password encryption method
1. Create class: MyPasswordEncoder
package com.example.cas.password; import org.springframework.security.crypto.password.PasswordEncoder; /** * Password encryption */ public class MyPasswordEncoder implements PasswordEncoder { @Override public String encode(CharSequence charSequence) { System.out.println("encode===========Password entered by the user:" + charSequence); return charSequence.toString(); } @Override public boolean matches(CharSequence charSequence, String str) { //charSequence is the password entered by the user System.out.println("matches---------------Password entered by the user:"+charSequence); //str is the database password System.out.println("matches---------------Database password:"+str); if (charSequence.equals(str)){ return true; } return false; } }
2,application.properties configuration file
#Turn on custom password authentication cas.authn.jdbc.query[0].passwordEncoder.type=com.example.cas.MyPasswordEncoder
3. The cas server can customize the theme, that is, the login page, or other pages
1,pom.xml
<!--Custom login page start--> <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-core-webflow-api</artifactId> <version>${cas.version}</version> </dependency> <!--Custom login page end-->
2. Register json and create services / login-10000001 under resources json, the topic name is loginTheme
{ "@class" : "org.apereo.cas.services.RegexRegisteredService", "serviceId" : "^(https|http|imaps)://.*", "name" : "web", "id" : 10000001, "evaluationOrder" : 10, "accessStrategy" : { "@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", "enabled" : true, "ssoEnabled" : true }, "theme": "loginTheme" }
3. Configuration file: application Properties enable json code scanning
# Service registry # Open the JSON file. The default is false. Here is the way to open the JSON file in the services cas.serviceRegistry.initFromJson=true #Auto scan service configuration, enabled by default cas.serviceRegistry.watcherEnabled=true #Scan every 120 seconds cas.serviceRegistry.schedule.repeatInterval=120000 #Delay 15 seconds on # cas.serviceRegistry.schedule.startDelay=15000 cas.serviceRegistry.json.location=classpath:/services #JSON file subject name loginTheme cas.theme.defaultThemeName=loginTheme
4. Create logintheme under resources properties
loginTheme.javascript.file=/themes/loginTheme/js/cas.js loginTheme.standard.css.file=/themes/loginTheme/css/cas.css loginTheme.login.images.path=/themes/loginTheme/images cas.standard.css.file=/css/cas.css cas.javascript.file=/js/cas.js cas.admin.css.file=/css/admin.css
Create static resources and login files. The path is as follows:
# Static resource file resources/static/themes/loginTheme/css/cas.css resources/static/themes/loginTheme/js/cas.js resources/static/themes/loginTheme/images/ # Login page resources/templates/loginTheme/casLoginView.html
5,casLoginView.html: the name is fixed. You can't fool around. The page content can be your own. The following page is a copy of the cas login page.
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" th:src="@{/themes/customTheme/js/cas.js}"></script> <script type="text/javascript" th:src="@{/themes/customTheme/js/jquery.min.js}"></script> </head> <body> <span>Login page</span><br> <form method="post" id="fm1" th:object="${credential}" action="login"> <div class="alert alert-danger" th:if="${#fields.hasErrors('*')}"> <span th:each="err : ${#fields.errors('*')}" th:utext="${err}">Example error</span> </div> <h3 th:utext="#{screen.welcome.instructions}">Enter your Username and Password</h3> <section class="form-group"> <label for="username" th:utext="#{screen.welcome.label.netid}">Username</label> <div th:if="${openIdLocalId}"> <strong> <span th:utext="${openIdLocalId}"/> </strong> <input type="hidden" id="username" name="username" th:value="${openIdLocalId}"/> </div> <div th:unless="${openIdLocalId}"> <input class="form-control required" id="username" size="25" tabindex="1" type="text" th:disabled="${guaEnabled}" th:field="*{username}" th:accesskey="#{screen.welcome.label.netid.accesskey}" autocomplete="off"/> </div> </section> <section class="form-group"> <label for="password" th:utext="#{screen.welcome.label.password}">Password</label> <div> <input class="form-control required" type="password" id="password" size="25" tabindex="2" th:accesskey="#{screen.welcome.label.password.accesskey}" th:field="*{password}" autocomplete="off"/> <span id="capslock-on" style="display:none;"> <p> <i class="fa fa-exclamation-circle"></i> <span th:utext="#{screen.capslock.on}"/> </p> </span> </div> </section> <section class="form-group"> <label for="telephone">Telephone</label> <div th:if="${openIdLocalId}"> <strong> <span th:utext="${openIdLocalId}"/> </strong> <input type="hidden" id="telephone" name="username" th:value="${openIdLocalId}"/> </div> <div th:unless="${openIdLocalId}"> <input class="form-control required" id="telephone" size="25" tabindex="1" type="text" th:disabled="${guaEnabled}" th:field="*{telephone}" th:accesskey="#{screen.welcome.label.netid.accesskey}" autocomplete="off"/> </div> </section> <section class="form-check" th:if="${passwordManagementEnabled && param.doChangePassword != null}"> <p> <input type="checkbox" name="doChangePassword" id="doChangePassword" value="true" th:checked="${param.doChangePassword != null}" tabindex="4"/> <label for="doChangePassword" th:text="#{screen.button.changePassword}">Change Password</label> </p> </section> <section class="form-check" th:if="${rememberMeAuthenticationEnabled}"> <p> <input type="checkbox" name="rememberMe" id="rememberMe" value="true" tabindex="5"/> <label for="rememberMe" th:text="#{screen.rememberme.checkbox.title}">Remember Me</label> </p> </section> <section class="row" th:if="${recaptchaSiteKey != null AND recaptchaInvisible != null AND recaptchaSiteKey != null AND !recaptchaInvisible}"> <div class="g-recaptcha" th:attr="data-sitekey=${recaptchaSiteKey}"/> </section> <input type="hidden" name="execution" th:value="${flowExecutionKey}"/> <input type="hidden" name="_eventId" value="submit"/> <input type="hidden" name="geolocation"/> <p th:if="${#request.getMethod().equalsIgnoreCase('POST')}"> <span th:each="entry : ${httpRequestInitialPostParameters}" th:remove="tag"> <span th:each="entryValue : ${entry.value}" th:remove="tag"> <input type="hidden" th:name="${entry.key}" th:value="${entryValue}"/> </span> </span> </p> <input class="btn btn-block btn-submit" th:unless="${recaptchaSiteKey != null AND recaptchaInvisible != null AND recaptchaSiteKey != null AND recaptchaInvisible}" name="submit" accesskey="l" th:value="#{screen.welcome.button.login}" tabindex="6" type="submit" value="Login3"/> <button class="btn btn-block btn-submit g-recaptcha" th:if="${recaptchaSiteKey != null AND recaptchaInvisible != null AND recaptchaSiteKey != null AND recaptchaInvisible}" th:attr="data-sitekey=${recaptchaSiteKey}, data-badge=${recaptchaPosition}" data-callback="onSubmit" name="submitBtn" accesskey="l" th:text="#{screen.welcome.button.login}" tabindex="6"/> </form> </body> </html>
4. The cas server adds fields to the form submitted during login
Add fields to the login form
1. Create a class that accepts new fields in the form: CustomCredential
package com.example.cas.login; import org.apereo.cas.authentication.UsernamePasswordCredential; public class CustomCredential extends UsernamePasswordCredential { private String telephone; public String getTelephone() { return telephone; } public void setTelephone(String telephone) { this.telephone = telephone; } }
2. Add custom field class: CustomWebflowConfigurer
package com.example.cas.config; import com.example.cas.login.CustomCredential; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.web.flow.CasWebflowConstants; import org.apereo.cas.web.flow.configurer.AbstractCasWebflowConfigurer; import org.springframework.context.ApplicationContext; import org.springframework.webflow.definition.registry.FlowDefinitionRegistry; import org.springframework.webflow.engine.Flow; import org.springframework.webflow.engine.ViewState; import org.springframework.webflow.engine.builder.BinderConfiguration; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; /** * Add custom field * @author anumbrella */ public class CustomWebflowConfigurer extends AbstractCasWebflowConfigurer { public CustomWebflowConfigurer(FlowBuilderServices flowBuilderServices, FlowDefinitionRegistry flowDefinitionRegistry, ApplicationContext applicationContext, CasConfigurationProperties casProperties) { super(flowBuilderServices, flowDefinitionRegistry, applicationContext, casProperties); } @Override protected void doInitialize() { final Flow flow = super.getLoginFlow(); bindCredential(flow); } /** * Bind custom Credential information * @param flow */ protected void bindCredential(Flow flow) { // Override binding custom credential createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, CustomCredential.class); //Bind new parameters to login page final ViewState state = (ViewState) flow.getState(CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM); final BinderConfiguration cfg = getViewStateBinderConfiguration(state); // Since the user name and password have been bound, you only need to bind the newly added system parameters // Field name, converter, whether the field must be telephone: it is a newly added field, and multiple fields can be added cfg.addBinding(new BinderConfiguration.Binding("telephone", null, true)); cfg.addBinding(new BinderConfiguration.Binding("phone", null, true)); } }
3. Add custom field class to configuration: CustomerAuthWebflowConfiguration
package com.example.cas.config; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.web.flow.CasWebflowConfigurer; import org.apereo.cas.web.flow.CasWebflowExecutionPlan; import org.apereo.cas.web.flow.CasWebflowExecutionPlanConfigurer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.webflow.definition.registry.FlowDefinitionRegistry; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; /** * Configure add custom field class */ @Configuration("customerAuthWebflowConfiguration") @EnableConfigurationProperties(CasConfigurationProperties.class) public class CustomerAuthWebflowConfiguration implements CasWebflowExecutionPlanConfigurer { @Autowired private CasConfigurationProperties casProperties; @Autowired @Qualifier("loginFlowRegistry") private FlowDefinitionRegistry loginFlowDefinitionRegistry; @Autowired private ApplicationContext applicationContext; @Autowired private FlowBuilderServices flowBuilderServices; @Bean public CasWebflowConfigurer customWebflowConfigurer() { //Instantiate a custom form configuration class final CustomWebflowConfigurer c = new CustomWebflowConfigurer(flowBuilderServices, loginFlowDefinitionRegistry, applicationContext, casProperties); // initialization c.initialize(); // Return object return c; } @Override public void configureWebflowExecutionPlan(final CasWebflowExecutionPlan plan) { plan.registerWebflowConfigurer(customWebflowConfigurer()); } }
4. In document resources / meta-inf / spring In factories, add configuration:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.cas.config.CustomerAuthWebflowConfiguration
5. cas server custom login verification
1,pom.xml
<!--Custom login verification start--> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-json-service-registry</artifactId> <version>${cas.version}</version> </dependency> <!-- Custom Authentication --> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-core-authentication-api</artifactId> <version>${cas.version}</version> </dependency> <!-- Custom Configuration --> <dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-core-configuration-api</artifactId> <version>${cas.version}</version> </dependency> <!--Custom login verification end-->
2. Custom verification class: CustomUsernamePasswordAuthentication
package com.example.cas.login; import com.example.cas.Model.UserInfo; import com.example.cas.Model.CustomCredential; import org.apereo.cas.authentication.*; import org.apereo.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler; import org.apereo.cas.authentication.principal.PrincipalFactory; import org.apereo.cas.services.ServicesManager; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; import javax.security.auth.login.AccountLockedException; import javax.security.auth.login.FailedLoginException; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * Custom login verification */ public class CustomUsernamePasswordAuthentication extends AbstractPreAndPostProcessingAuthenticationHandler { public CustomUsernamePasswordAuthentication(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) { super(name, servicesManager, principalFactory, order); } @Override public boolean supports(Credential credential) { //Judge whether the passed Credential is a type that you can handle return credential instanceof CustomCredential; } /** * Authentication, that is, login * @param credential * @return * @throws GeneralSecurityException * @throws PreventedException */ @Override protected AuthenticationHandlerExecutionResult doAuthentication(Credential credential) throws GeneralSecurityException, PreventedException { System.out.println("++========================="+4); UsernamePasswordCredential usernamePasswordCredential = (UsernamePasswordCredential) credential; String username = usernamePasswordCredential.getUsername(); String password = usernamePasswordCredential.getPassword(); System.out.println("******CustomUsernamePasswordAuthentication******: " + username); System.out.println("******CustomUsernamePasswordAuthentication******: " + password); /*Query database data through jdbc*/ // JDBC template depends on connection pool to obtain data connection, so connection pool must be constructed first DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/shiro?useUnicode=true&characterEncoding=utf-8"); dataSource.setUsername("root"); dataSource.setPassword("123456"); // Create JDBC template JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); String sql = "SELECT * FROM system_admin_user WHERE account = ?"; UserInfo info = (UserInfo) jdbcTemplate.queryForObject(sql, new Object[]{username}, new BeanPropertyRowMapper(UserInfo.class)); System.out.println("database username : "+ info.getAccount()); System.out.println("database password : "+ info.getPassword()); //The abnormality here is not good. It won't work if (info != null) { throw new AccountLockedException(); } if (!info.getPassword().equals(password)) { throw new FailedLoginException("Sorry, Incorrect password!"); } else { //Multiple attribute information returned to the client can be customized HashMap<String, Object> returnInfo = new HashMap<>(); returnInfo.put("id", info.getId()); returnInfo.put("account", info.getAccount()); returnInfo.put("disableStatus", info.getDisableStatus()); final List<MessageDescriptor> list = new ArrayList<>(); return createHandlerResult(usernamePasswordCredential, this.principalFactory.createPrincipal(username, returnInfo), list); } } }
3. Injection configuration: CustomAuthenticationConfiguration
package com.example.cas.login; import org.apereo.cas.authentication.AuthenticationEventExecutionPlan; import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer; import org.apereo.cas.authentication.AuthenticationHandler; import org.apereo.cas.authentication.principal.DefaultPrincipalFactory; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.services.ServicesManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Injection configuration information */ @Configuration("CustomAuthenticationConfiguration") @EnableConfigurationProperties(CasConfigurationProperties.class) public class CustomAuthenticationConfiguration implements AuthenticationEventExecutionPlanConfigurer { @Autowired private ServicesManager servicesManager; @Bean public AuthenticationHandler myAuthenticationHandler() { // Parameters: name, servicesManager, principalFactory, order // Defined as the priority to use it for authentication return new CustomUsernamePasswordAuthentication(CustomUsernamePasswordAuthentication.class.getName(), servicesManager, new DefaultPrincipalFactory(), 1); } @Override public void configureAuthenticationExecutionPlan(final AuthenticationEventExecutionPlan plan) { plan.registerAuthenticationHandler(myAuthenticationHandler()); } }
4. In document resources / meta-inf / spring In factories, add configuration:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.cas.login.CustomAuthenticationConfiguration
Note: the exception return in the above custom login is not allowed.
6. cas server custom return exception
7. The cas server uses ajax to log in
There is no time for these two directories.