当前位置:网站首页>Our company has used this set of general solutions for 7 years, and has opened up dozens of systems, a stable batch!
Our company has used this set of general solutions for 7 years, and has opened up dozens of systems, a stable batch!
2022-06-30 11:44:00 【Migrant worker brother】
Click below “Java Programming duck ” Follow and mark the stars
More exciting First time direct
Preface
What is single sign on ? Full single sign on name Single Sign On( hereinafter referred to as SSO), Log in to a system in a multi system application group , Can be authorized on all other systems without having to log in again , Including single sign on and single sign off , Pictured ( Nonstandard , It's just easy to understand ).

One 、CAS What is it? ?
CAS yes Yale An open source project initiated by the University , For the purpose of Web The application system provides a reliable single sign on method ,CAS stay 2004 year 12 The month officially became JA-SIG A project for .CAS It has the following characteristics :
Open source enterprise single sign on solution .
CAS Server For those that need to be deployed independently Web application .
CAS Client Support a lot of clients ( This refers to the single sign on system Web application ), Include Java, .Net, PHP, Perl, Apache, uPortal, Ruby etc. .
Two 、 Build client system
1. introduce CAS
Note that the certificate is imported into jdk in , Be sure to be precise cacerts Under this document , Otherwise, it will always be reported that it refuses to write , In addition, it is better to use the command window under the administrator
2. Client backend setup
1. Add dependency
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.5</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
2. Configure client
server:
port: 1234
3. add to config(filter)
file
All addresses are ip, If you use hosts Mapping address , There may be problems
package com.casclient1.cas.config;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.util.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.filter.CharacterEncodingFilter;
import javax.servlet.Filter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class FilterConfig implements Serializable, InitializingBean {
private static final Logger LOGGER = LoggerFactory.getLogger(FilterConfig.class);
public static final String CAS_SIGNOUT_FILTER_NAME = "CAS Single Sign Out Filter";
public static final String CAS_AUTH_FILTER_NAME = "CAS Filter";
public static final String CAS_IGNOREL_SSL_FILTER_NAME = "CAS Ignore SSL Filter";
public static final String CAS_FILTER_NAME = "CAS Validation Filter";
public static final String CAS_WRAPPER_NAME = "CAS HttpServletRequest Wrapper Filter";
public static final String CAS_ASSERTION_NAME = "CAS Assertion Thread Local Filter";
public static final String CHARACTER_ENCODING_NAME = "Character encoding Filter";
//CAS Server exit address
private static String casSigntouServerUrlPrefix = "https://127.0.0.1:8443/cas/logout";
//CAS Server login address
private static String casServerLoginUrl = "https://127.0.0.1:8443/cas/login";
// Client address
private static String clienthosturl="http://127.0.0.1:1234";
//CAS Server address
private static String casValidationServerUrlPrefix = "https://127.0.0.1:8443/cas";
public FilterConfig() {
}
/**
* Single sign out function , Put it in the other filter Before
* casSigntouServerUrlPrefix Prefix logout :https://123.207.122.156:8081/cas/logout
*
* @return
*/
@Bean
@Order(0)
public FilterRegistrationBean getCasSignoutFilterRegistrationBean() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(getCasSignoutFilter());
registration.addUrlPatterns("/*", "*.html");
registration.addInitParameter("casServerUrlPrefix", casSigntouServerUrlPrefix);
registration.setName(CAS_SIGNOUT_FILTER_NAME);
registration.setEnabled(true);
return registration;
}
@Bean(name = CAS_SIGNOUT_FILTER_NAME)
public Filter getCasSignoutFilter() {
return new SingleSignOutFilter();
}
/**
* Ignore SSL authentication
*
* @return
*/
@Bean
@Order(1)
public FilterRegistrationBean getCasSkipSSLValidationFilterRegistrationBean() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(getCasSkipSSLValidationFilter());
registration.addUrlPatterns("/*", "*.html");
registration.setName(CAS_IGNOREL_SSL_FILTER_NAME);
registration.setEnabled(true);
return registration;
}
@Bean(name = CAS_IGNOREL_SSL_FILTER_NAME)
public Filter getCasSkipSSLValidationFilter() {
return new IgnoreSSLValidateFilter();
}
/**
* Responsible for user authentication
* casServerLoginUrl:https://123.207.122.156:8081/cas/login
* casServerName:https://123.207.122.156:8080/tdw/alerts/
*
* @return
*/
@Bean
@Order(2)
public FilterRegistrationBean getCasAuthFilterRegistrationBean() {
FilterRegistrationBean registration = new FilterRegistrationBean();
final Filter casAuthFilter = getCasAuthFilter();
registration.setFilter(casAuthFilter);
registration.addUrlPatterns("/*", "*.html");
registration.addInitParameter("casServerLoginUrl", casServerLoginUrl);
registration.addInitParameter("serverName", clienthosturl);
registration.setName(CAS_AUTH_FILTER_NAME);
registration.setEnabled(true);
return registration;
}
@Bean(name = CAS_AUTH_FILTER_NAME)
public Filter getCasAuthFilter() {
return new MyAuthenticationFilter();
}
/**
* Yes Ticket check
* casValidationServerUrlPrefix Use the intranet ip
* casValidationServerUrlPrefix:https://123.207.122.156:8081/cas
* casServerName:https://123.207.122.156:8080/tdw/alerts/
*
* @return
*/
@Bean
@Order(3)
public FilterRegistrationBean getCasValidationFilterRegistrationBean() {
FilterRegistrationBean registration = new FilterRegistrationBean();
final Filter casValidationFilter = getCasValidationFilter();
registration.setFilter(casValidationFilter);
registration.addUrlPatterns("/*", "*.html");
registration.addInitParameter("casServerUrlPrefix", casValidationServerUrlPrefix);
registration.addInitParameter("serverName", clienthosturl);
registration.setName(CAS_FILTER_NAME);
registration.setEnabled(true);
return registration;
}
@Bean(name = CAS_FILTER_NAME)
public Filter getCasValidationFilter() {
return new Cas20ProxyReceivingTicketValidationFilter();
}
/**
* Set up response The default encoding of :UTF-8.
*
* @return
*/
@Bean
@Order(4)
public FilterRegistrationBean getCharacterEncodingFilterRegistrationBean() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(getCharacterEncodingFilter());
registration.addUrlPatterns("/*", "*.html");
registration.setName(CHARACTER_ENCODING_NAME);
registration.setEnabled(true);
return registration;
}
@Bean(name = CHARACTER_ENCODING_NAME)
public Filter getCharacterEncodingFilter() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
return characterEncodingFilter;
}
@Bean
public FilterRegistrationBean casHttpServletRequestWrapperFilter(){
FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
authenticationFilter.setFilter(new HttpServletRequestWrapperFilter());
authenticationFilter.setOrder(6);
List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/*");
authenticationFilter.setUrlPatterns(urlPatterns);
return authenticationFilter;
}
@Override
public void afterPropertiesSet() throws Exception {
}
}
4.filter Class MyAuthenticationFilter
It's rewriting cas jar In bag AuthenticationFilter
, as a result of CAS The source code cannot authenticate the direct redirection , and ajax Requests cannot be redirected directly , Leading to the front end 302, and 302vue response Interceptors cannot intercept . So I thought of not letting cas Redirect me , Return the status code to me , Tell the front end that authentication failed , Let the front end jump directly cas Server login address .
modify cas Source filter , Copy source code AuthenticationFilter
This filter , Rewrite him , In fact, only the redirection code is changed here. Everything else is the same . On MyAuthenticationFilter
Code
package com.casclient1.cas.config;
import org.jasig.cas.client.authentication.*;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.ReflectUtils;
import org.jasig.cas.client.validation.Assertion;
import javax.servlet.FilterConfig;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class MyAuthenticationFilter extends AbstractCasFilter {
private String casServerLoginUrl;
private boolean renew = false;
private boolean gateway = false;
private GatewayResolver gatewayStorage = new DefaultGatewayResolverImpl();
private AuthenticationRedirectStrategy authenticationRedirectStrategy = new DefaultAuthenticationRedirectStrategy();
private UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass = null;
private static final Map<String, Class<? extends UrlPatternMatcherStrategy>> PATTERN_MATCHER_TYPES = new HashMap();
public MyAuthenticationFilter() {
}
@Override
protected void initInternal(FilterConfig filterConfig) throws ServletException {
if (!this.isIgnoreInitConfiguration()) {
super.initInternal(filterConfig);
this.setCasServerLoginUrl(this.getPropertyFromInitParams(filterConfig, "casServerLoginUrl", (String)null));
this.logger.trace("Loaded CasServerLoginUrl parameter: {}", this.casServerLoginUrl);
this.setRenew(this.parseBoolean(this.getPropertyFromInitParams(filterConfig, "renew", "false")));
this.logger.trace("Loaded renew parameter: {}", this.renew);
this.setGateway(this.parseBoolean(this.getPropertyFromInitParams(filterConfig, "gateway", "false")));
this.logger.trace("Loaded gateway parameter: {}", this.gateway);
String ignorePattern = this.getPropertyFromInitParams(filterConfig, "ignorePattern", (String)null);
this.logger.trace("Loaded ignorePattern parameter: {}", ignorePattern);
String ignoreUrlPatternType = this.getPropertyFromInitParams(filterConfig, "ignoreUrlPatternType", "REGEX");
this.logger.trace("Loaded ignoreUrlPatternType parameter: {}", ignoreUrlPatternType);
if (ignorePattern != null) {
Class<? extends UrlPatternMatcherStrategy> ignoreUrlMatcherClass = (Class)PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);
if (ignoreUrlMatcherClass != null) {
this.ignoreUrlPatternMatcherStrategyClass = (UrlPatternMatcherStrategy) ReflectUtils.newInstance(ignoreUrlMatcherClass.getName(), new Object[0]);
} else {
try {
this.logger.trace("Assuming {} is a qualified class name...", ignoreUrlPatternType);
this.ignoreUrlPatternMatcherStrategyClass = (UrlPatternMatcherStrategy)ReflectUtils.newInstance(ignoreUrlPatternType, new Object[0]);
} catch (IllegalArgumentException var6) {
this.logger.error("Could not instantiate class [{}]", ignoreUrlPatternType, var6);
}
}
if (this.ignoreUrlPatternMatcherStrategyClass != null) {
this.ignoreUrlPatternMatcherStrategyClass.setPattern(ignorePattern);
}
}
String gatewayStorageClass = this.getPropertyFromInitParams(filterConfig, "gatewayStorageClass", (String)null);
if (gatewayStorageClass != null) {
this.gatewayStorage = (GatewayResolver)ReflectUtils.newInstance(gatewayStorageClass, new Object[0]);
}
String authenticationRedirectStrategyClass = this.getPropertyFromInitParams(filterConfig, "authenticationRedirectStrategyClass", (String)null);
if (authenticationRedirectStrategyClass != null) {
this.authenticationRedirectStrategy = (AuthenticationRedirectStrategy)ReflectUtils.newInstance(authenticationRedirectStrategyClass, new Object[0]);
}
}
}
@Override
public void init() {
super.init();
CommonUtils.assertNotNull(this.casServerLoginUrl, "casServerLoginUrl cannot be null.");
}
@Override
public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
if (this.isRequestUrlExcluded(request)) {
this.logger.debug("Request is ignored.");
filterChain.doFilter(request, response);
} else {
HttpSession session = request.getSession(false);
Assertion assertion = session != null ? (Assertion)session.getAttribute("_const_cas_assertion_") : null;
if (assertion != null) {
filterChain.doFilter(request, response);
} else {
String serviceUrl = this.constructServiceUrl(request, response);
String ticket = this.retrieveTicketFromRequest(request);
boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if (!CommonUtils.isNotBlank(ticket) && !wasGatewayed) {
this.logger.debug("no ticket and no assertion found");
String modifiedServiceUrl;
if (this.gateway) {
this.logger.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
this.logger.debug("Constructed service url: {}", modifiedServiceUrl);
String xRequested =request.getHeader("x-requested-with");
if("XMLHttpRequest".equals(xRequested)){
response.getWriter().write("{\"code\":202, \"msg\":\"no ticket and no assertion found\"}");
}else{
String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
this.logger.debug("redirecting to \"{}\"", urlToRedirectTo);
this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
}
} else {
filterChain.doFilter(request, response);
}
}
}
}
public final void setRenew(boolean renew) {
this.renew = renew;
}
public final void setGateway(boolean gateway) {
this.gateway = gateway;
}
public final void setCasServerLoginUrl(String casServerLoginUrl) {
this.casServerLoginUrl = casServerLoginUrl;
}
public final void setGatewayStorage(GatewayResolver gatewayStorage) {
this.gatewayStorage = gatewayStorage;
}
private boolean isRequestUrlExcluded(HttpServletRequest request) {
if (this.ignoreUrlPatternMatcherStrategyClass == null) {
return false;
} else {
StringBuffer urlBuffer = request.getRequestURL();
if (request.getQueryString() != null) {
urlBuffer.append("?").append(request.getQueryString());
}
String requestUri = urlBuffer.toString();
return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri);
}
}
static {
PATTERN_MATCHER_TYPES.put("CONTAINS", ContainsPatternUrlPatternMatcherStrategy.class);
PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class);
PATTERN_MATCHER_TYPES.put("EXACT", ExactUrlPatternMatcherStrategy.class);
}
}
test Controller
package com.casclient1.cas.controller;
import com.casclient1.cas.domain.UserDomain;
import com.casclient1.cas.tools.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Console;
import java.io.IOException;
@Controller
public class TestController {
/**
* test
* @return
*/
@GetMapping("/test")
@ResponseBody
public Result<UserDomain> login(HttpServletRequest httpServletRequest){
System.out.println("sss");
return new Result<>(new UserDomain(httpServletRequest.getRemoteUser()));
}
@GetMapping("/checkTicket")
public void index(HttpServletResponse response) throws IOException {
// Front page address
response.sendRedirect("http://127.0.0.1:8088/Home");
}
/**
* Cancellation
* @return
*/
@RequestMapping("/logout")
public String logout(){
return "redirect:https://127.0.0.1:8443/cas/logout";
}
}
3. front end
<template xmlns="http://www.w3.org/1999/html">
<div >
<header style="height: 60px">
<span> client 2 verification :{
{name}}</span>
<button @click="logout"> Safety exit </button>
</header>
<router-view></router-view>
<!--
<my-vue v-bind:lineID="lineID"></my-vue>-->
</div>
</template>
<style lang="scss">
</style>
<script type="text/ecmascript-6">
export default {
data() {
return {
name:'ss'
}
},
mounted(){
var _this = this;
this.$http.get('/test', {headers: {'x-requested-with': 'XMLHttpRequest'}})
.then(function (response) {
console.log("sss");
if (response.data.code === 202) {
debugger
console.log("sss");
window.location.href = "http://127.0.0.1:1235/checkTicket"
} else if (response.data.code === 200) {
console.log("sss");
_this.name = response.data.data.name
}
console.log(response);
})
.catch(function (error) {
console.log(error);
});
},
methods: {
logout() {
window.location.href = "http://127.0.0.1:1234/logout"
},
}
}
</script>
5. effect
Not logged in :

Click client 1 Hyperlinks

Login successful

Click client 2 Hyperlinks , Go straight into , No need to log in .

sign out

summary
There are many on the Internet CAS Single sign on demo, However, there is little detail about the separation of front and rear ends , Fore and aft end separation , There must be cross domain , Lead to CAS Login cannot be redirected, etc , Combined with some ideas and department codes on the Internet , We have made a relatively perfect , But a very basic single sign on System , Of course, single sign on is not just about CAS, also JWT(1. All services are generated by contract token,2. Or generate and judge in a centralized way , All services can recognize this , Or a service can control the whole situation ),OAuth2 wait .
blog.csdn.net/weixin_43483911/article/details/117811270
END
After reading this article, there are gains ? Please forward to share with more people
Focus on 「Java Programming duck 」, promote Java Skill
Focus on Java Programming duck WeChat official account , The background to reply : Yard farm gift bag A copy of the latest technical data can be obtained . cover Java Frame learning 、 Architect learning, etc !
If the article helps , Looking at , Forward! .
Thank you for your support (*^__^*)
边栏推荐
- What is a wechat applet that will open the door of the applet
- Pointdistiller: structured knowledge distillation for efficient and compact 3D detection
- The first batch in China! Alibaba cloud native data Lake products have passed the evaluation and certification of the ICT Institute
- Esp32-c3 introductory tutorial basic part ⑪ - reading and writing non-volatile storage (NVS) parameters
- promise async和await的方法与使用
- 微信表情符号被写入判决书,你发的每个 emoji 都可能成为呈堂证供
- Speech signal processing - Fundamentals (V): Fourier transform
- "War" caused by a bottle of water
- 使用cookie技术实现历史浏览记录并控制显示的个数
- What is erdma as illustrated by Coptic cartoon?
猜你喜欢
How to analyze native crash through GDB
再不上市,旷视科技就熬不住了
HMS core audio editing service 3D audio technology helps create an immersive auditory feast
There are so many kinds of coupons. First distinguish them clearly and then collect the wool!
以PolarDB为代表的阿里云数据库以跻身全球第一阵营
Limited time appointment | Apache pulsar Chinese developer and user group meeting in June
Is the golden cycle of domestic databases coming?
一个悄然崛起的国产软件,低调又强大!
Dameng data rushes to the scientific innovation board, or becomes the "first share of domestic database" in the A-share market
Esp32-c3 introductory tutorial question ⑨ - core 0 panic 'ed (load access fault) Exception was unhandled. vfprintf. c:1528
随机推荐
What is erdma as illustrated by Coptic cartoon?
【西安交通大学】考研初试复试资料分享
Qualcomm released the "magic mirror" of the Internet of things case set, and digital agriculture has become a reality
Xu Lei expressed three thanks for the most difficult 618 in 19 years
If it is not listed again, Kuangshi technology will not be able to endure
MCU firmware packaging Script Software
wallys/IPQ8074a/2x(4×4 or 8×8) 11AX MU-MIMO DUAL CONCURRENT EMBEDDEDBOARD
Oracle netsuite helps TCM bio understand data changes and make business development more flexible
数据库 级联操作
dplyr 中的filter报错:Can‘t transform a data frame with duplicate names
CVPR 2022 | greatly reduce the manual annotation required for zero sample learning. Mapu and Beiyou proposed category semantic embedding rich in visual information
Object mapping - mapping Mapster
Lucene full text search toolkit learning notes summary
数据库连接池 druid
[applet practice series] Introduction to the registration life cycle of the applet framework page
Go语言学习之Switch语句的使用
A theoretical defect of relative position coding transformer and Its Countermeasures
Alibaba cloud database represented by polardb ranks first in the world
Mathematics (fast power)
博弈论入门