java面试之单点登录

1. 单点

单点登录SSO(Single Sign On)是目前比较流行的企业业务整合解决方案之一。在分布式服务中,用户只需要在一处登录,即可在各个受信任的服务器之间,共享登录状态。

实现单点登录有多种方式,其区别在于是否能解决跨域登录。

实现单点登录的关键在于如何让 Session ID(或 Token)在多个域中共享。

2. 实现方式

cookie

Cookie 作用域由 domain 属性和 path 属性共同决定。

同域名不同站点

www.lymn.com/site、www.lymn.com/site2

HTTP协议天然支持同一个域名下两个站点共享cookie。

用户登录了site1,浏览器将会保存一个cookie,对应默认域名是www.lymn.com,用户访问site2,浏览器判断是同一个域名,将会在请求中加入cookie信息。

在这里插入图片描述

不同子域父域 Cookie

d1.lymn.com、d2.lymn.com

默认情况下浏览器请求时,服务器根据域名发送对应cookie。来自于d1.lymn.com的cookie默认所属域是d1.lymn.com,请求d2.lymn.com时不会发送d1cookie。

基于这种情况,用户登录d1.lymn.com后,服务端将cookie所属域名设置为.sso.com并返回,浏览器将会保存.sso.com和cookie的对应关系。当用户访问d2.lymn.com时,将会携带.sso.com对应的cookie。

在这里插入图片描述

专用的代理服务器

CAS

CAS 包含两个部分: CAS Server 和 CAS Client。

CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。

TGT:Ticket Granted Ticket(俗称大令牌,或者说票根,它可以签发ST)。用户在CAS认证成功后,CAS生成cookie(叫TGC),写入浏览器,同时生成一个TGT对象,放入自己的缓存,TGT对象的ID就是cookie的值。
TGC:Ticket Granted Cookie(cookie中的value),存在Cookie中,根据它可以找到TGT。
ST:Service Ticket (小令牌),是TGT生成的,默认是用一次就生效了。

CAS特点

  • 开源的企业级单点登录解决方案
  • CAS Server 为需要独立部署的 Web 应用
  • CAS Client 支持非常多的客户端(这里指单点登录系统中的各个 Web 应用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。

下图是CAS 最基本协议过程:
在这里插入图片描述

  • 当用户第一次请求cas客户端1http://localhost:8080/lymn/index,会经过AuthenticationFilter认证过滤器
  • AuthenticationFilter则返回浏览器重定向地址。重定向地址就是认证服务器CAS Server登录的地址,后面的参数是我们请求的客户端地址
  • 浏览器根据响应地址,发起重定向,用户登陆页面输入用户名密码,提交请求
  • CAS Server 认证服务器接收用户名和密码,进行验证,根据请求参数service的值,进行重定向,其实就是回到了请求的客户端,同时会携带一个ticket令牌参数,并且在Cookie中设置一个TGC
  • 客户端拿到请求中的ticket(ST)信息,经过一个ticket过滤器Cas20ProxyReceivingTicketValidationFilter,去认证系统CAS Server判断ticket是否有效
  • 通过校验之后,把用户信息保存到客户端服务的session中,并把客户端服务的SessionID设置在Cookie中,同时告知客户端ticket有效。当用户再次访问该客户端,就可以根据Cookie 中的SessionID找到客户端服务的Session,获取用户信息,就不用再次进行验证了
  • 当用户第二次请求cas客户端1http://localhost:8080/lymn/index,仍然会经过AuthenticationFilter过滤器,此时客户端服务session中已经存在用户的信息,浏览器中的Cookie会根据SessionID找到Session,获取用户信息,所以不需要进行验证,直接访问
  • 当用户第一次请求cas客户端2http://localhost:8081/lymn/index,经过AuthenticationFilter认证过滤器
  • AuthenticationFilter则返回浏览器重定向地址,去找认证中心登录
  • 浏览器根据响应地址,发起重定向,因为之前访问过一次了,因此这次会携带上次返回的Cookie:TGC到认证中心
  • CAS Server认证中心收到请求,发现TGC对应了一个TGT,于是用TGT签发一个ticket,并且返回给浏览器,让他重定向到http://localhost:8081/lymn/index
  • 浏览器客户端带着ticket,经过一个ticket过滤器Cas20ProxyReceivingTicketValidationFilter,去认证中心验证是否有效
  • 认证成功,把用户信息保存到客户端服务的session中,并把客户端服务的SessionID设置在Cookie中。当用户下次访问http://localhost:8081/lymn/index,直接访问

注:当下次访问cas Server认证系统时,浏览器将Cookie中的TGC携带到服务器,服务器根据这个TGC,查找与之对应的TGT。从而判断用户是否登录过了,是否需要展示登录页面。TGT与TGC的关系就像SESSION与Cookie中SESSIONID的关系。

在这里插入图片描述

全局会话与局部会话有如下约束关系

  1. 局部会话存在,全局会话一定存在
  2. 全局会话存在,局部会话不一定存在
  3. 全局会话销毁,局部会话必须销毁

在一个子系统中注销,sso认证中心一直监听全局会话的状态,一旦全局会话销毁,监听器将通知所有注册系统执行注销操作。

在这里插入图片描述

应用

CAS Server :一个war包,CAS框架已经提供。只需要把部署到web服务器上即可,主要负责对用户的认证工作。

CAS Client:开发过程中的web层, 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server,简单配置即可。

CAS服务端配置

1)引入CAS客户端相关依赖

 <dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-support-jdbc</artifactId>
    <version>5.2.2</version>
</dependency>
<dependency>
   <groupId>org.apereo.cas</groupId>
   <artifactId>cas-server-support-jdbc-drivers</artifactId>
   <version>5.2.2</version>
</dependency>
<dependency>
    <groupId>com.ibm.informix</groupId>
    <artifactId>jdbc</artifactId>
    <version>4.10.7.20160517</version>
</dependency>

2) application.properties配置

server.context-path=/cas
server.port=8443
#开启识别json文件
cas.serviceRegistry.initFromJson=true
cas.tgc.secure=false

server.ssl.enabled=true
server.ssl.key-store=classpath:thekeystore
server.ssl.key-store-password=picc@1234
server.ssl.key-password=changeit
server.ssl.keyAlias=caskeystore
cas.logout.followServiceRedirects=true
slo.callbacks.disabled=true
#cas.authn.accept.users=casuser::Mellon

##
# CAS Thymeleaf View Configuration
#
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=true
spring.thymeleaf.mode=HTML

cas.authn.jdbc.query[0].url=jdbc:informix-sqli://18.1.32.25:5955/zjk:informixserver=shanxi_fxdata;NEWCODESET=GBK,8859-1,819,Big5;IFX_USE_STRENC=true
cas.authn.jdbc.query[0].user=ccpqry
cas.authn.jdbc.query[0].password=ccpqry
cas.authn.jdbc.query[0].driverClass=com.informix.jdbc.IfxDriver
cas.authn.jdbc.query[0].fieldPassword=password
cas.authn.jdbc.query[0].sql=select * from yh_user_login where userid=? and valid='1'
cas.authn.jdbc.query[0].dialect=oorg.hibernate.dialect.Informix10Dialect

3) resources 文件夹下创建 services 文件夹,创建HTTPSandIMAPS-10000001.json,添加http

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(https|imaps|http)://.*",
  "name" : "HTTPS and IMAPS",
  "id" : 10000001,
  "description" : "This service definition authorizes all application urls that support HTTPS and IMAPS protocols.",
  "evaluationOrder" : 10000
}

4) resources 文件夹下创建messages_zh_CN.properties,可对这些信息进行替换

# 该用户不存在
authenticationFailure.AccountNotFoundException=\u8be5\u7528\u6237\u4e0d\u5b58\u5728
# 用户名或者密码错误
authenticationFailure.FailedLoginException=\u7528\u6237\u540d\u6216\u8005\u5bc6\u7801\u9519\u8bef
# 这个账户被禁用了
authenticationFailure.AccountDisabledException=\u8fd9\u4e2a\u8d26\u6237\u88ab\u7981\u7528\u4e86\u3002
# 这个账号锁了
authenticationFailure.AccountLockedException=\u8fd9\u4e2a\u8d26\u6237\u88ab\u4e0a\u9501\u4e86\u3002
# 密码过期了
authenticationFailure.CredentialExpiredException=\u4f60\u7684\u5bc6\u7801\u8fc7\u671f\u4e86\u3002

5)编译后部署到tomcat,配置conf.xml,添加如下内容后,启动该服务

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">
        <SSLHostConfig>
            <Certificate certificateKeystoreFile="D:/ca/thekeystore"
                         type="RSA" certificateKeystoreType="JKS" certificateKeystorePassword="picc@1234"/>
        </SSLHostConfig>
</Connector>

CAS客户端配置

1)引入CAS客户端相关依赖

<dependency>
    <groupId>org.jasig.cas.client</groupId>
    <artifactId>cas-client-core</artifactId>
    <version>3.2.2</version>
</dependency>

2)web.xml

<!-- 该过滤器用于实现单点登出功能,可选配置。 -->
<listener>
		<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
	</listener>
	<filter>
		<filter-name>casSingleSignOutFilter</filter-name>
		<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
		<init-param>
			<param-name>casServerUrlPrefix</param-name>
			<param-value>http://18.1.34.186/cas/</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>casSingleSignOutFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
<!-- 该过滤器负责用户的认证工作,必须启用它 -->
<filter>
		<filter-name>CASFilter</filter-name>
		<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
		<init-param>
			<param-name>casServerLoginUrl</param-name>
			<param-value>http://18.1.34.186/cas/login</param-value>
		</init-param>
		<init-param>
			<param-name>serverName</param-name>
             <!-- 客户端地址,用于认证成功后,跳转回客户端 -->
			<param-value>http://18.1.34.186</param-value>
		</init-param>
		<init-param>
			<param-name>renew</param-name>
			<param-value>false</param-value>
		</init-param>
		<init-param>
			<param-name>gateway</param-name>
			<param-value>false</param-value>
		</init-param>
		<init-param>
			<param-name>ignorePattern</param-name>
			<param-value>/css/|/js/</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CASFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
<!-- 该过滤器负责对 Ticket 的校验工作,必须启用它 -->
<filter>  
        <filter-name>CAS Validation Filter</filter-name>  
        <filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>  
        <init-param>  
            <param-name>casServerUrlPrefix</param-name>  
            <param-value>http://18.1.34.186/cas</param-value>  
        </init-param>  
        <init-param>  
            <param-name>serverName</param-name> 
             <!-- 客户端地址,用于认证成功后,跳转回客户端 -->
            <param-value>http://18.1.34.186</param-value>  
        </init-param>  
        <init-param>
			<param-name>useSession</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<param-name>redirectAfterValidation</param-name>
			<param-value>true</param-value>
		</init-param>
    </filter>  
    <filter-mapping>  
        <filter-name>CAS Validation Filter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  
 <!-- 该过滤器负责实现 HttpServletRequest 请求的包裹, 比如允许开发者通过HttpServletRequest 的 getRemoteUser()方法获得 SSO 登录用户的登录名,可选配置。 -->
<filter>
		<filter-name>casHttpServletRequestWrapperFilter</filter-name>
		<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>casHttpServletRequestWrapperFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
 <!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder 来获取用户的登录名。 AssertionHolder.getAssertion().getPrincipal().getName()。 -->
<filter>
		<filter-name>casAssertionThreadLocalFilter</filter-name>
		<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>casAssertionThreadLocalFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

3)后台获取用户名及跨域设置

public class ToolUtil {
    public static String getUserName(HttpServletRequest request){
    	Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
		String userName = null;
		if (assertion != null) {
		    AttributePrincipal principal = assertion.getPrincipal();
		    userName = principal.getName();
		}
		return userName;
    	
    }
}
@Component
public class CorsFilter implements Filter{
	@Override  
    public void destroy() {  
          
    }  
  
    @Override  
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {  
    	 HttpServletResponse response = (HttpServletResponse) resp;
         response.setHeader("Access-Control-Allow-Origin","*");
         response.setHeader("Access-Control-Allow-Method","POST,GET,OPTIONS,DELETE");
         response.setHeader("Access-Control-Max-Age","3600");
         response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type");
         response.setHeader("Access-Control-Allow-Credentials", "true");
         chain.doFilter(req,resp);
          
    }  
  
    @Override  
    public void init(FilterConfig arg0) throws ServletException {  
          
    }  
}

CAS客户端springboot配置

1)引入CAS客户端相关依赖

<dependency>
    <groupId>net.unicon.cas</groupId>
    <artifactId>cas-client-autoconfig-support</artifactId>
    <version>1.5.0-GA</version>
</dependency>

2) application.properties配置

#cas配置
cas.server-url-prefix=http\://18.1.34.186/cas
cas.server-login-url=http\://18.1.34.186/cas/login
cas.client-host-url=http\://18.1.34.186\:80
mycas.client-url=http\://18.1.34.186\:80/portal
cas.validation-type=CAS

3)FilterConfig配置类

@Configuration
public class FilterConfig  extends CasClientConfigurerAdapter{
	
	@Value("${cas.server-login-url}")
    private String CAS_URL;
    @Override
    public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) {
        super.configureAuthenticationFilter(authenticationFilter);
        //authenticationFilter.getInitParameters().put("authenticationRedirectStrategyClass","com.patterncat.CustomAuthRedirectStrategy");
    }
    @Bean
    public ServletListenerRegistrationBean servletListenerRegistrationBean(){
        ServletListenerRegistrationBean  listenerRegistrationBean = new ServletListenerRegistrationBean();
        listenerRegistrationBean.setListener(new SingleSignOutHttpSessionListener());
        listenerRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return listenerRegistrationBean;
    }
    /**
     * 单点登录退出
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean singleSignOutFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new SingleSignOutFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.addInitParameter("casServerUrlPrefix", CAS_URL);
        registrationBean.setName("CAS Single Sign Out Filter");
        registrationBean.setOrder(1);
        return registrationBean;
    }
}

4)获取用户名

public class ToolUtil {
    public static String getUserName(HttpServletRequest request){
            Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
            String userName = null;
            if (assertion != null) {
                AttributePrincipal principal = assertion.getPrincipal();
                userName = principal.getName();
            }
            return userName;

        }
}

5)在启动类中添加cas client注解:@EnableCasClient

CAS 自定义登录验证

1)自定义登录页面,src/main/resources下创建templates,新casLoginView.html

<div class="main-body">
    <div class="login-main">
        <div class="login-top">
            <span>单点登录系统</span>
            <span class="bg1"></span>
            <span class="bg2"></span>
        </div>
        <form class="layui-form login-bottom " id="form" th:object="${credential}" method="post" action="login">
            <div class="alert alert-danger" th:if="${#fields.hasErrors('*')}">
				<span th:each="err : ${#fields.errors('*')}" th:utext="${err}"></span>
			</div>
			<div class="center">
                <div class="item">
                    <span class="icon icon-2"></span>
                    <input type="text" name="username" lay-verify="required" lay-reqtext="用户名不能为空" th:field="*{username}" placeholder="请输入登录账号" maxlength="24"/>
                </div>

                <div class="item">
                    <span class="icon icon-3"></span>
                    <input type="password" lay-verify="pass" id="password" name="password"   th:field="*{password}" placeholder="请输入密码" maxlength="20">
                    <span class="bind-password icon icon-4"></span>
                </div>
            </div>
             <div class="tip">
                <a class="forget-password" target="_blank" href="pwd">修改密码</a>
            </div>
            <div class="layui-form-item" style="text-align:center; width:100%;height:100%;margin:0px;">
				<input type="hidden" name="execution" th:value="${flowExecutionKey}"/>
                <input type="hidden" name="_eventId" value="submit"/>
                <input type="hidden" name="geolocation"/>
			   <button class="login-btn" lay-submit="" lay-filter="login">登录</button>
            </div>
        </form>
    </div>
</div>
<div class="footer">
    ©版权所有 2019-2021 <a target="_blank" href="#">LYMN</a>
</div>
<script src="layui-v2.5.5/layui.js" charset="utf-8"></script> 
<script>
    layui.use(['form','jquery'], function () {
        var $ = layui.jquery,
            form = layui.form,
            layer = layui.layer;
        form.verify({
 		   pass: [
 /^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&.,;_+=/-])[A-Za-z\d$@$!%*#?&.,;_+=/-]{8,20}$/
 		      ,'密码不符合规则,请修改密码'
 		    ]
 		  }); 
        // 登录过期的时候,跳出ifram框架
        if (top.location != self.location) top.location = self.location;

        $('.bind-password').on('click', function () {
            if ($(this).hasClass('icon-5')) {
                $(this).removeClass('icon-5');
                $("input[name='password']").attr('type', 'password');
            } else {
                $(this).addClass('icon-5');
                $("input[name='password']").attr('type', 'text');
            }
        });
        $("#password").blur(function () {
      	  var reg =  /^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&.,;_+=/-])[A-Za-z\d$@$!%*#?&.,;_+=/-]{8,20}$/
                var password = $("#password").val();
                //    用正则取匹配内容
                var result = reg.test(password);
                if (!result) {
              	layer.msg('密码不符合规则,请修改密码',{time:1*2000, icon: 2});
	                return false;  
                }
        });
        // 进行登录操作
        form.on('submit(login)', function (data) {
            data = data.field;
            if (data.username == '') {
                layer.msg('用户名不能为空');
                return false;
            }
            if (data.password == '') {
                layer.msg('密码不能为空');
                return false;
            }
            $("#form").submit();
            return false;
        });
    });
</script>

2)实体类

@Getter
@Setter
public class User  implements Serializable {
    private String userid;//工号
    private String username;//姓名
    private String epassword;//加密密码
    private String salt;//加盐值
    private String password;//明文密码
    private Date update_date;
}

3) 引入依赖

<dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>java-property-utils</artifactId>
    <version>1.9</version>
</dependency>
<dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>cors-filter</artifactId>
    <version>2.5</version>
</dependency>
<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-core-authentication</artifactId>
    <version>5.2.2</version>
</dependency>
<dependency>
    <groupId>org.apereo.cas</groupId>
 <artifactId>cas-server-core-api-authentication</artifactId>
    <version>5.2.2</version>
</dependency>

4)认证方式仅仅是传用户名和密码,实现AbstractUsernamePasswordAuthenticationHandler抽象类;提交的信息不止用户名和密码,就需继承AbstractPreAndPostProcessingAuthenticationHandler抽象类,AbstractUsernamePasswordAuthenticationHandler是继承实现的这个类,它只是用于简单用户名和密码校验。

public class CustomerHandler extends AbstractPreAndPostProcessingAuthenticationHandler {

	public CustomerHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory,
	            Integer order) {
	        super(name, servicesManager, principalFactory, order);
	    }

	    /**
	     * 用于判断用户的Credential(换而言之,就是登录信息),子站点的登录信息中不止有用户名密码等信息,还有部门信息的情况
	     */
	    @Override
	    public boolean supports(Credential credential) {
	        //判断传递过来的Credential 是否是自己能处理的类型
	        return credential instanceof UsernamePasswordCredential;
	    }

	    /**
	     * 用于登录处理
	     */
	    @Override
	    protected HandlerResult doAuthentication(Credential credential) throws GeneralSecurityException, PreventedException {
	        UsernamePasswordCredential usernamePasswordCredentia = (UsernamePasswordCredential) credential;

	        //获取传递过来的用户名和密码
	        String username = usernamePasswordCredentia.getUsername();
	        String password = usernamePasswordCredentia.getPassword();
	     // 验证用户名和密码
			DriverManagerDataSource d = new DriverManagerDataSource();
			d.setDriverClassName("com.informix.jdbc.IfxDriver");
			d.setUrl(
					"jdbc:informix-sqli://18.1.32.25:5955/zjk:informixserver=shanxi_fxdata;NEWCODESET=GBK,8859-1,819,Big5;IFX_USE_STRENC=true");
			d.setUsername("ccpqry");
			d.setPassword("ccpqry");
	 
			JdbcTemplate template = new JdbcTemplate();
			template.setDataSource(d);
	 
			// 查询数据库加密的的密码
			Map<String, Object> user = template.queryForMap("select salt,epassword from yh_user_login  where userid=?",
					username);
	       
	        //判断加密后的输入密码是否与数据库的相同
	        if(ShiroUtil.decrypt(password, user.get("salt").toString(), user.get("epassword").toString())){
	            return createHandlerResult(credential, this.principalFactory.createPrincipal(username, Collections.emptyMap()), null);
	        }
	        throw new FailedLoginException("密码输入错误");
	    }
}

5)注入配置信息,继承AuthenticationEventExecutionPlanConfigurer

@Configuration
@ComponentScan("com.picc.cas.*")
@MapperScan("com.picc.cas.mapper")
public class SpringConfig implements AuthenticationEventExecutionPlanConfigurer{
	  @Autowired
	    @Qualifier("servicesManager")
	    private ServicesManager servicesManager;
	//配置数据源
    @Bean
    public DataSource dataSource(){

        DriverManagerDataSource dataSource= new DriverManagerDataSource("jdbc:informix-sqli://18.1.32.25:5955/zjk:informixserver=shanxi_fxdata;NEWCODESET=GBK,8859-1,819,Big5;IFX_USE_STRENC=true","ccpqry","ccpqry");
        dataSource.setDriverClassName("com.informix.jdbc.IfxDriver");
        return dataSource;
    }

   //配置 mybatis自动扫描 Mapper
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer mapperScannerConfigurer=new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("com.picc.cas.mapper");
        return mapperScannerConfigurer;
    }
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource());

        ResourcePatternResolver resourcePatternResolver=new PathMatchingResourcePatternResolver();
        //配置扫描对应路径的xml
        factoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath*:mapper/*.xml"));
        factoryBean.setTypeAliasesPackage("com.picc.cas.model");
        return factoryBean.getObject();
    }
  
    @Bean
    public AuthenticationHandler customAuthenticationHandler() {
    	return new CustomerHandler("customerHandler",
                servicesManager, new DefaultPrincipalFactory(), 1);
    }

    public void configureAuthenticationExecutionPlan(AuthenticationEventExecutionPlan plan) {
        plan.registerAuthenticationHandler(customAuthenticationHandler());
    }
}

6)在src/main/resources目录下新建META-INF目录,新建spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.picc.cas.SpringConfig

参考

CAS单点登录原理分析(一)

SSO 单点登录

CAS之5.2x版本单点登录服务安装-yellowcong

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值