CAS5.3服务端配置,链接mysql、自定义密码加密、登录页面、登录校验,自定义异常、ajax登录等

目录

1、cas服务端配置mysql
2、cas服务端自定义密码加密方式
3、cas服务端自定义主题,也就是登录页面,也可以其他的页面
4、cas服务端在登录时提交的表单中添加字段
5、cas服务端自定义登录校验
6、cas服务端自定义返回异常
7、cas服务端使用ajax进行登录

环境:

CAS版本:5.3

下载链接:git地址是:https://github.com/apereo/cas-overlay-template

tomcat:8

jdk:1.8

1、先把cas服务端的源代码拷贝出来,方法如下:

1)使用idea打开

红框中是通过idea配置tomcat后,编译出来的代码。

 2)创建src目录,如下,并且把target/cas/META-INF文件、target/cas/services、target/cas/application.properties,这三个文件拷贝到resources中。

由于CAS默认支持https,如果想要改成支持http,获取一些其他CAS服务端的基本配置,那么可以看这篇文章:SSO单点登录(一)创建CAS服务端_我是混IT圈的-CSDN博客_cas服务器搭建

1、cas服务端配置mysql

 1、pom.xml

<!--数据库认证相关 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>
        <!--数据库认证相关 end-->

2、application.properties 配置文件

1)添加与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 #数据库账号
cas.authn.jdbc.query[0].password=123456  #数据库密码
cas.authn.jdbc.query[0].sql=select password from system_admin_user where account = ?  #表的查询sql
cas.authn.jdbc.query[0].fieldPassword=password  #表中属于密码的字段

2)注释掉cas默认的帐号密码,不然这个账号密码也是可以登录的

#cas.authn.accept.users=casuser::Mellon

注意:这里使用mysql进行登录,密码是没有经过加密的,比如,登录密码是123456,那么数据库的密码就是123456。

2、cas服务端自定义密码加密方式

 1、创建类:MyPasswordEncoder

package com.example.cas.password;

import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * 密码加密
 */
public class MyPasswordEncoder implements PasswordEncoder {

    @Override
    public String encode(CharSequence charSequence) {
        System.out.println("encode===========用户输入的密码:" + charSequence);
        return charSequence.toString();
    }

    @Override
    public boolean matches(CharSequence charSequence, String str) {
        //charSequence 为用户输入的密码
        System.out.println("matches---------------用户输入的密码:"+charSequence);
        //str 为数据库密码
        System.out.println("matches---------------数据库密码:"+str);
        if (charSequence.equals(str)){
            return true;
        }
        return false;
    }
}

2、application.properties 配置文件

#开启自定义密码验证
cas.authn.jdbc.query[0].passwordEncoder.type=com.example.cas.MyPasswordEncoder

3、cas服务端自定义主题,也就是登录页面,也可以其他的页面

1、pom.xml

<!--自定义登录页面 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>
        <!--自定义登录页面 end-->

2、注册 json,resources 下创建 services/login-10000001.json,主题名称为 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、配置文件:application.properties  开启json扫码

# Service Registry(服务注册)
# 开启识别Json文件,默认false,这里就是开启识别 services 中的json文件的
cas.serviceRegistry.initFromJson=true
#自动扫描服务配置,默认开启
cas.serviceRegistry.watcherEnabled=true
#120秒扫描一遍
cas.serviceRegistry.schedule.repeatInterval=120000
#延迟15秒开启
# cas.serviceRegistry.schedule.startDelay=15000
cas.serviceRegistry.json.location=classpath:/services
#JSON文件主题名称 loginTheme
cas.theme.defaultThemeName=loginTheme

4、在resources下创建 loginTheme.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

创建静态资源和登录文件,路径如下:

# 静态资源文件
resources/static/themes/loginTheme/css/cas.css
resources/static/themes/loginTheme/js/cas.js
resources/static/themes/loginTheme/images/
# 登录页面
resources/templates/loginTheme/casLoginView.html

5、casLoginView.html:名称是固定的,不能瞎干,页面内容可以自己些,下面这个页面是拷贝的cas登录页面。

<!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>登录页面</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">电话</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、cas服务端在登录时提交的表单中添加字段

在登录表单中添加字段

1、创建接受表单中新增的字段的类: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、添加自定义字段类: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;

/**
 * 添加自定义字段
 * @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);
    }

    /**
     * 绑定自定义的 Credential 信息
     * @param flow
     */
    protected void bindCredential(Flow flow) {
        // 重写绑定自定义credential
        createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, CustomCredential.class);
        //登录页绑定新参数
        final ViewState state = (ViewState) flow.getState(CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM);
        final BinderConfiguration cfg = getViewStateBinderConfiguration(state);
        // 由于用户名以及密码已经绑定,所以只需对新加系统参数绑定即可
        // 字段名,转换器,是否必须字段  telephone:它是新添加的字段,可以添加多个字段
        cfg.addBinding(new BinderConfiguration.Binding("telephone", null, true));
        cfg.addBinding(new BinderConfiguration.Binding("phone", null, true));
    }
}

3、配置 添加自定义字段 类: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;

/**
 * 配置 添加自定义字段 类
 */
@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() {
        //实例化自定义的表单配置类
        final CustomWebflowConfigurer c = new CustomWebflowConfigurer(flowBuilderServices, loginFlowDefinitionRegistry,
                applicationContext, casProperties);
        // 初始化
        c.initialize();
        // 返回对象
        return c;
    }

    @Override
    public void configureWebflowExecutionPlan(final CasWebflowExecutionPlan plan) {
        plan.registerWebflowConfigurer(customWebflowConfigurer());
    }
}

4、在文件 resources/META-INF/spring.factories 中,添加配置:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.cas.config.CustomerAuthWebflowConfiguration

5、cas服务端自定义登录校验

1、pom.xml

<!--自定义登录校验 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>
        <!--自定义登录校验 end-->

2、自定义校验类: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;


/**
 * 自定义登录校验
 */
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) {
        //判断传递过来的Credential 是否是自己能处理的类型
        return credential instanceof CustomCredential;
    }

    /**
     * 身份验证,也就是登录
     * @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);

        /*通过jdbc查询数据库的数据*/
        // JDBC模板依赖于连接池来获得数据的连接,所以必须先要构造连接池
        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");
        // 创建JDBC模板
        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());

        //这里的异常还不行,用不了的
        if (info != null) {
            throw new AccountLockedException();
        }
        if (!info.getPassword().equals(password)) {
            throw new FailedLoginException("Sorry, 密码不正确!");
        } else {
            //可自定义返回给客户端的多个属性信息
            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、注入配置 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;

/**
 * 注入配置信息
 */
@Configuration("CustomAuthenticationConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CustomAuthenticationConfiguration implements AuthenticationEventExecutionPlanConfigurer {
    @Autowired
    private ServicesManager servicesManager;

    @Bean
    public AuthenticationHandler myAuthenticationHandler() {
        // 参数: name, servicesManager, principalFactory, order
        // 定义为优先使用它进行认证
        return new CustomUsernamePasswordAuthentication(CustomUsernamePasswordAuthentication.class.getName(),
                servicesManager, new DefaultPrincipalFactory(), 1);
    }

    @Override
    public void configureAuthenticationExecutionPlan(final AuthenticationEventExecutionPlan plan) {
        plan.registerAuthenticationHandler(myAuthenticationHandler());
    }
}

4、在文件 resources/META-INF/spring.factories 中,添加配置:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.cas.login.CustomAuthenticationConfiguration

注意:上面自定义登录中的异常返回,是不行的。

6、cas服务端自定义返回异常
7、cas服务端使用ajax进行登录

这两个目录没有时间搞了。

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值