Cas之5.2.x版本单点登录自定义REST认证-yellowcong

来源:互联网 发布:淘宝虚拟现实购物 编辑:程序博客网 时间:2024/06/13 00:56

通过接口的方式进行单点登录的操作。REST这种方式是解决验证数据不在CAS服务端,而是在本地端项目源码地址:https://gitee.com/yellowcong/cas_demo/tree/master/cas_rest_demo ,这个破玩意折腾了我3天,才写出来,新累啊,官方文档太坑。

再次强调一下,我是5.2.x版本,jdk 1.8 和tomcat 8.5,源码地址:https://gitee.com/yellowcong/cas_demo/tree/master/cas_rest_demo

架构

节点 服务 127.0.0.1:8080 CAS(单点服务) https://127.0.0.1:8443/cas CAS 127.0.0.1:8081 rest-client(认证服务)

安装准备

建议先搞好了cas的服务安装,再来完这个
CAS之5.2x版本单点登录服务安装-yellowcong

Cas服务配置

这里写图片描述

pom.xml

下面的配置很多,但是都是默认的,而且我这个主要的是添加了 rest验证的依赖包

<dependency>        <groupId>org.jasig.cas</groupId>        <artifactId>cas-server-support-rest-authentication</artifactId>        <version>4.2.3.RELEASE</version>        <scope>system</scope>        <type>jar</type>        <optional>true</optional>        <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/cas-server-support-rest-authentication-5.2.0.jar</systemPath>    </dependency>

官方文档
这里写图片描述

pom.xml 完整配置

<?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>org.apereo.cas</groupId>    <artifactId>cas-overlay</artifactId>    <packaging>war</packaging>    <version>1.0</version>    <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>${mainClassName}</mainClass>                    <addResources>true</addResources>                    <executable>${isExecutable}</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>2.6</version>                <configuration>                    <warName>cas</warName>                    <failOnMissingWebXml>false</failOnMissingWebXml>                    <recompressZippedFiles>false</recompressZippedFiles>                    <archive>                        <compress>false</compress>                        <manifestFile>${manifestFileToUse}</manifestFile>                    </archive>                    <overlays>                        <overlay>                            <groupId>org.apereo.cas</groupId>                            <artifactId>cas-server-webapp${app.server}</artifactId>                        </overlay>                    </overlays>                </configuration>            </plugin>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <version>3.3</version>            </plugin>        </plugins>        <finalName>cas</finalName>    </build>    <dependencies>        <dependency>            <groupId>org.apereo.cas</groupId>            <artifactId>cas-server-webapp${app.server}</artifactId>            <version>${cas.version}</version>            <type>war</type>            <scope>system</scope>            <optional>true</optional>            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/cas-server-webapp-tomcat-5.2.0.war</systemPath>        </dependency>        <!--引入rest认证相关 start -->        <dependency>            <groupId>org.jasig.cas</groupId>            <artifactId>cas-server-support-rest-authentication</artifactId>            <version>4.2.3.RELEASE</version>            <scope>system</scope>            <type>jar</type>            <optional>true</optional>            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/cas-server-support-rest-authentication-5.2.0.jar</systemPath>        </dependency>        <!--引入rest认证相关 end -->        <!-- 权限验证的加密包 -->        <dependency>            <groupId>org.springframework.security</groupId>            <artifactId>spring-security-core</artifactId>            <version>4.2.3.RELEASE</version>            <scope>system</scope>            <type>jar</type>            <optional>true</optional>            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/spring-security-core-4.2.3.RELEASE.jar</systemPath>        </dependency>        <!-- spring security end -->        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-core</artifactId>            <version>1.3.2</version>        </dependency>    </dependencies>    <properties>        <cas.version>5.2.0</cas.version>        <springboot.version>1.5.8.RELEASE</springboot.version>        <!-- app.server could be -jetty, -undertow, -tomcat, or blank if you plan             to provide appserver -->        <app.server>-tomcat</app.server>        <mainClassName>org.springframework.boot.loader.WarLauncher</mainClassName>        <isExecutable>false</isExecutable>        <manifestFileToUse>${project.build.directory}/war/work/org.apereo.cas/cas-server-webapp${app.server}/META-INF/MANIFEST.MF</manifestFileToUse>        <maven.compiler.source>1.8</maven.compiler.source>        <maven.compiler.target>1.8</maven.compiler.target>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    </properties>    <repositories>        <repository>            <id>sonatype-releases</id>            <url>http://oss.sonatype.org/content/repositories/releases/</url>            <snapshots>                <enabled>false</enabled>            </snapshots>            <releases>                <enabled>true</enabled>            </releases>        </repository>        <repository>            <id>sonatype-snapshots</id>            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>            <snapshots>                <enabled>true</enabled>            </snapshots>            <releases>                <enabled>false</enabled>            </releases>        </repository>        <repository>            <id>shibboleth-releases</id>            <url>https://build.shibboleth.net/nexus/content/repositories/releases</url>        </repository>    </repositories>    <profiles>        <profile>            <activation>                <activeByDefault>true</activeByDefault>            </activation>            <id>exec</id>            <properties>                <mainClassName>org.apereo.cas.web.CasWebApplication</mainClassName>                <isExecutable>true</isExecutable>                <manifestFileToUse></manifestFileToUse>            </properties>            <build>                <plugins>                    <plugin>                        <groupId>com.soebes.maven.plugins</groupId>                        <artifactId>echo-maven-plugin</artifactId>                        <version>0.3.0</version>                        <executions>                            <execution>                                <phase>prepare-package</phase>                                <goals>                                    <goal>echo</goal>                                </goals>                            </execution>                        </executions>                        <configuration>                            <echos>                                <echo>Executable profile to make the generated CAS web                                    application executable.</echo>                            </echos>                        </configuration>                    </plugin>                </plugins>            </build>        </profile>        <profile>            <activation>                <activeByDefault>false</activeByDefault>            </activation>            <id>pgp</id>            <build>                <plugins>                    <plugin>                        <groupId>com.github.s4u.plugins</groupId>                        <artifactId>pgpverify-maven-plugin</artifactId>                        <version>1.1.0</version>                        <executions>                            <execution>                                <goals>                                    <goal>check</goal>                                </goals>                            </execution>                        </executions>                        <configuration>                            <pgpKeyServer>hkp://pool.sks-keyservers.net</pgpKeyServer>                            <pgpKeysCachePath>${settings.localRepository}/pgpkeys-cache</pgpKeysCachePath>                            <scope>test</scope>                            <verifyPomFiles>true</verifyPomFiles>                            <failNoSignature>false</failNoSignature>                        </configuration>                    </plugin>                </plugins>            </build>        </profile>    </profiles></project>

application.properties 配置

添加rest验证的服务端

#请求远程调用接口,相当于远程获取数据源#http://127.0.0.1:8081/cas-rest/user/logincas.authn.rest.uri=http://127.0.01:8081/cas-rest/user/login#加密策略cas.authn.rest.passwordEncoder.type=DEFAULTcas.authn.rest.passwordEncoder.characterEncoding=UTF-8#加密算法cas.authn.rest.passwordEncoder.encodingAlgorithm=MD5

官方文档
这里写图片描述

application.properties完整配置

### CAS Server Context Configuration#server.context-path=/casserver.port=8443#添加认证服务cas.serviceRegistry.initFromJson=true#STEP 4签发证书,如果是用spring boot之类嵌入式的容器,则需要改这里的配置,如果是直接部在tomcat中,则需要把tomcat改成https的#server.ssl.key-store=file:/etc/cas/thekeystore#server.ssl.key-store-password=changeit#server.ssl.key-password=changeit# server.ssl.ciphers=# server.ssl.client-auth=# server.ssl.enabled=# 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=#server.max-http-header-size=2097152#server.use-forward-headers=true#server.connection-timeout=20000#server.error.include-stacktrace=ALWAYS#server.compression.enabled=true#server.compression.mime-types=application/javascript,application/json,application/xml,text/html,text/xml,text/plain#server.tomcat.max-http-post-size=2097152#server.tomcat.basedir=build/tomcat#server.tomcat.accesslog.enabled=true#server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)#server.tomcat.accesslog.suffix=.log#server.tomcat.max-threads=10#server.tomcat.port-header=X-Forwarded-Port#server.tomcat.protocol-header=X-Forwarded-Proto#server.tomcat.protocol-header-https-value=https#server.tomcat.remote-ip-header=X-FORWARDED-FOR#server.tomcat.uri-encoding=UTF-8spring.http.encoding.charset=UTF-8spring.http.encoding.enabled=truespring.http.encoding.force=true### 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=trueendpoints.enabled=falseendpoints.sensitive=trueendpoints.restart.enabled=falseendpoints.shutdown.enabled=falsemanagement.security.enabled=truemanagement.security.roles=ACTUATOR,ADMINmanagement.security.sessions=if_requiredmanagement.context-path=/statusmanagement.add-application-context-header=falsesecurity.basic.authorize-mode=rolesecurity.basic.enabled=falsesecurity.basic.path=/cas/status/**### CAS Web Application Session Configuration#server.session.timeout=300server.session.cookie.http-only=trueserver.session.tracking-modes=COOKIE### CAS Thymeleaf View Configuration#spring.thymeleaf.encoding=UTF-8spring.thymeleaf.cache=falsespring.thymeleaf.mode=HTML### CAS Log4j Configuration## logging.config=file:/etc/cas/log4j2.xmlserver.context-parameters.isLog4jAutoInitializationDisabled=true### CAS AspectJ Configuration#spring.aop.auto=truespring.aop.proxy-target-class=true### CAS Authentication Credentials##cas.authn.accept.users=casuser::Mellon#REST 认证#请求远程调用接口,相当于远程获取数据源#http://127.0.0.1:8081/cas-rest/user/logincas.authn.rest.uri=http://127.0.01:8081/cas-rest/user/login#加密策略cas.authn.rest.passwordEncoder.type=DEFAULTcas.authn.rest.passwordEncoder.characterEncoding=UTF-8#加密算法cas.authn.rest.passwordEncoder.encodingAlgorithm=MD5

rest证服务

工程目录

Srping+SpringMVC+Mybatis搭建的,数据库是MySQL
这里写图片描述

CasUser.java

package com.yellowcong.cas.model;import java.util.HashMap;import java.util.Map;import org.codehaus.jackson.annotate.JsonProperty;/** * 创建日期:2017年12月18日  * 创建时间:下午10:44:58  * 创建者 :yellowcong  * 机能概要:用于传递给CAS服务器验证数据 */public class CasUser {    @JsonProperty("id")    private String username;    @JsonProperty("@class")    // 需要返回实现org.apereo.cas.authentication.principal.Principal的类名接口    private String clazz = "org.apereo.cas.authentication.principal.SimplePrincipal";    @JsonProperty("attributes")    private Map<String, Object> attributes = new HashMap<String,Object>();    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getClazz() {        return clazz;    }    public void setClazz(String clazz) {        this.clazz = clazz;    }    public Map<String, Object> getAttributes() {        return attributes;    }    public void setAttributes(Map<String, Object> attributes) {        this.attributes = attributes;    }}

官网返回的json数据不正确
这里写图片描述

UserController.java

这里写图片描述

package com.yellowcong.controller;import java.io.IOException;import java.io.PrintWriter;import java.io.UnsupportedEncodingException;import javax.servlet.http.HttpServletResponse;import org.codehaus.jackson.map.ObjectMapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Scope;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Controller;import org.springframework.util.Base64Utils;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.RequestHeader;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import com.yellowcong.cas.model.CasUser;import com.yellowcong.model.User;import com.yellowcong.service.UserService;/** * 创建日期:2017年9月23日 <br/> * 创建用户:yellowcong <br/> * 功能描述:用户控制成 */@Controller@RequestMapping("/user")@Scope("prototype")public class UserController {    @Autowired    private UserService userService;    /**     * 创建日期:2017年9月23日<br/>     * 创建用户:yellowcong<br/>     * 功能描述:用户登录操作     * @param username     * @param password     * @return     */    @RequestMapping(value="/login",method=RequestMethod.POST)    public void login(@RequestHeader HttpHeaders httpHeaders,HttpServletResponse response){        Object result = null;        try {            User userWeb = this.obtainUserFormHeader(httpHeaders);            //当没有 传递 参数的情况            if(userWeb == null){                result = new ResponseEntity<CasUser>(HttpStatus.NOT_FOUND);            }            //数据库查找            User dbUser = this.userService.login(userWeb.getUsername());            if (dbUser != null) {                if (!dbUser.getPassword().equals(userWeb.getPassword())) {                    //密码不匹配                    result = new ResponseEntity<CasUser>(HttpStatus.BAD_REQUEST);                }else if (dbUser.isDisable()) {                    //禁用 403                    result = new ResponseEntity<CasUser>(HttpStatus.FORBIDDEN);                }else if (dbUser.isLocked()) {                    //锁定 423                    result = new ResponseEntity<CasUser>(HttpStatus.LOCKED);                }else if (dbUser.isExpired()) {                    //过期 428                    result = new ResponseEntity<CasUser>(HttpStatus.PRECONDITION_REQUIRED);                }else{                    //正常的数据                    //直接返回User数据                    CasUser casUser = new CasUser();                    casUser.setUsername(dbUser.getUsername());                    result = casUser;                }            } else {                //不存在 404                result = new ResponseEntity<CasUser>(HttpStatus.NOT_FOUND);            }        } catch (UnsupportedEncodingException e) {            result = new ResponseEntity<CasUser>(HttpStatus.BAD_REQUEST);        }        //将数据输出到客户端        this.writeJSON(response, result);    }    /**     * 将授权加密的信息返回     * 根据请求头获取用户名及密码     *     * @param httpHeaders     * @return     * @throws UnsupportedEncodingException     */    private User obtainUserFormHeader(HttpHeaders httpHeaders) throws UnsupportedEncodingException {        /**         *         * This allows the CAS server to reach to a remote REST endpoint via a POST for verification of credentials.         * Credentials are passed via an Authorization header whose value is Basic XYZ where XYZ is a Base64 encoded version of the credentials.         */        //根据官方文档,当请求过来时,会通过把用户信息放在请求头authorization中,并且通过Basic认证方式加密        String authorization = httpHeaders.getFirst("authorization");//将得到 Basic Base64(用户名:密码)        if(StringUtils.isEmpty(authorization)){            return null;        }        String baseCredentials = authorization.split(" ")[1];        String usernamePassword = new String(Base64Utils.decodeFromString(baseCredentials), "UTF-8");//用户名:密码        String credentials[] = usernamePassword.split(":");        return new User(credentials[0], credentials[1]);    }    /**     * 在SpringMvc中获取到Session     * @return     */    @SuppressWarnings("rawtypes")    public void writeJSON(HttpServletResponse response,Object object){        try {            //设定编码             response.setCharacterEncoding("UTF-8");            //表示是json类型的数据            response.setContentType("application/json");            //获取PrintWriter 往浏览器端写数据            PrintWriter writer = response.getWriter();            //当是不正常的数据的时候,设定状态            if(object instanceof ResponseEntity) {                HttpStatus status = ((ResponseEntity) object).getStatusCode();                //设定状态码表                response.setStatus(status.value());            }            ObjectMapper mapper = new ObjectMapper(); //转换器            //获取到转化后的JSON 数据            String json = mapper.writeValueAsString(object);            //写数据到浏览器            writer.write(json);            //刷新,表示全部写完,把缓存数据都刷出去            writer.flush();            //关闭writer            writer.close();        } catch (IOException e) {            e.printStackTrace();        }    }}

接口测试

用户传递过来的时候,
那么请求头authorization=Basic Base64(admin+MD5(123))送后客户端必须响应一下数据,cas明确规定如下:

cas 服务端会通过post请求,并且把用户信息以”用户名:密码”进行Base64编码放在authorization请求头中
返回200状态码并且格式为

{“@class”:”org.apereo.cas.authentication.principal.SimplePrincipal”,”id”:”casuser”,”attributes”:{}}

是成功的; 返回状态码403用户不可用;404账号不存在;423账户被锁定;428过期;其他登录失败

插件使用火狐之RESTClient插件安装-yellowcong

1、配置授权
这里写图片描述

2、配置请求url
这里写图片描述

3、发送请求(200的)
这里写图片描述

json的返回值
这里写图片描述

4、随便测试一个其他的
这里写图片描述

测试CAS访问

注意数据库脚本我在后面放着

用户信息

这里写图片描述

测试登录

正常用户

这里写图片描述

测试结果
这里写图片描述

用户禁用

这里写图片描述

尴尬了,这个用户是禁用的,
这里写图片描述

数据库脚本

/*SQLyog v10.2 MySQL - 5.1.68-community : Database - yellowcong_cas_rest**********************************************************************//*!40101 SET NAMES utf8 */;/*!40101 SET SQL_MODE=''*/;/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;CREATE DATABASE /*!32312 IF NOT EXISTS*/`yellowcong_cas_rest` /*!40100 DEFAULT CHARACTER SET utf8 */;USE `yellowcong_cas_rest`;/*Table structure for table `yellowcong_users` */DROP TABLE IF EXISTS `yellowcong_users`;CREATE TABLE `yellowcong_users` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `password` varchar(32) DEFAULT NULL COMMENT '密码',  `username` varchar(32) DEFAULT NULL COMMENT '用户名',  `is_disable` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否禁用',  `is_locked` tinyint(1) DEFAULT '0' COMMENT '是否上锁',  `is_expired` tinyint(1) DEFAULT '0' COMMENT '是否过期',  PRIMARY KEY (`id`,`is_disable`)) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;/*Data for the table `yellowcong_users` */insert  into `yellowcong_users`(`id`,`password`,`username`,`is_disable`,`is_locked`,`is_expired`) values (1,'4748f3d238406505bd50e5accc3a8aa2','yellowcong',0,0,0),(12,'4748f3d238406505bd50e5accc3a8aa2','test',1,0,0),(13,'4748f3d238406505bd50e5accc3a8aa2','test2',0,1,0),(14,'637d1339e213d3ab2777c28e7002df52','doubi',0,0,1);/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

参考文章

https://apereo.github.io/cas/5.1.x/installation/Configuration-Properties.html
https://oss.sonatype.org/content/repositories/releases/org/apereo/cas/
http://blog.csdn.net/u010475041/article/details/77972605

阅读全文
0 0