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

本文介绍如何使用Rest方式配置CAS进行用户认证,包括Cas服务端配置、客户端实现细节及测试过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

玩过了JDBC方式认证CAS用户,那么接下来是一是Rest方式进行用户认证。

什么是Rest认证?
通过数据接口对用户进行认证

cas又是怎么做的?
通过请求接口,返回固定格式,进行对密码匹配,判断用户是否合法

什么场景下用rest认证?
用户数据存在远端、不允许cas直接访问数据库、cas不希望你知道帐号数据的表结构

一、准备工作
数据库沿用上一篇jdbc文章中的sql脚本

项目名 访问地址 说明
cas-overlay-template-master(springboot+meven) https://cas.server.com:8443/cas Cas服务器
cas_db(springboot+Gradle) https://localhost:8080/cas_db Cas客户端,提供用户登录授权验证api接口
二、Cas 服务配置
1、pom.xml 配置
由于Rest方式并不需要直接通过JDBC链接数据库,所以在上一节文章中介绍的JDBC和mysql驱动依赖项就可以删掉了,保留一个就可以了

Markup

org.apereo.cas
cas-server-support-rest-authentication
${cas.version}

浏览器Flash插件异常,复制失败!
2、application.properties配置
同样的,把上一篇文章介绍的jdbc配置可以删掉了,配置如下即可

Markdown

#

CAS Authentication Credentials

#

cas.authn.accept.users=tingfeng::tingfeng

#

REST 认证开始, 请求远程调用接口

#
cas.authn.rest.uri=http://localhost:8080/cas_db/user/login
cas.authn.rest.passwordEncoder.type=DEFAULT
cas.authn.rest.passwordEncoder.characterEncoding=UTF-8
cas.authn.rest.passwordEncoder.encodingAlgorithm=MD5
浏览器Flash插件异常,复制失败!
3、流程介绍
当用户点击登录后,cas会发送post请求到 http://localhost:8080/cas_db/login 并且把用户信息以”用户名:密码”进行Base64编码放在authorization请求头中

若输入用户名密码为:admin/123;那么请求头包括:authorization=Basic Base64(admin+MD5(123))

WX20180417-175848@2x.png

那么发送后客户端必须响应一下数据,cas明确规定如下:

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

200状态码:并且格式为{“@class”:”org.apereo.cas.authentication.principal.SimplePrincipal”,”id”:”casuser”,”attributes”:{}}是成功的;

403状态码:用户不可用;

404状态码:账号不存在;

423状态码:账户被锁定;

428状态码:过期;

其他登录失败

三、cas_db客户端介绍
使用SpringBoot+Gradle+MyBatis构建

SysUser.java
Java
package com.tingfeng.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.Map;

/**
* 机能概要:用于传递给CAS服务器验证数据
*/
public class SysUser {

@JsonProperty("id")
private String id;

@NotNull
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<>();

@JsonIgnore
private String password;

@JsonIgnore
//用户是否不可用
private boolean disabled = false;

@JsonIgnore
//用户是否过期
private boolean expired = false;

@JsonIgnore
//是否锁定
private boolean locked = false;

/** 省略getter和setter 自行补充**/

}
浏览器Flash插件异常,复制失败!
SysUserMapper.java
Java
package com.tingfeng.mapper;

import com.tingfeng.domain.SysUser;
import org.apache.ibatis.annotations.Select;

public interface SysUserMapper {

@Select("select * from sys_user where username=#{username}")
SysUser getSysUser(String username);

}
浏览器Flash插件异常,复制失败!
SysUserController.java
Java
package com.tingfeng.controller;

import com.tingfeng.domain.SysUser;
import com.tingfeng.mapper.SysUserMapper;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;

@RestController
@RequestMapping(“/user”)
public class SysUserController {
private Logger logger = LogManager.getLogger(SysUserController.class);

@Autowired
private SysUserMapper sysUserMapper;

@PostMapping("/login")
public Object login(@RequestHeader HttpHeaders httpHeaders) {
    logger.info("Rest api login.");
    logger.debug("request headers: " + httpHeaders);
    SysUser user = null;
    try {
        UserTemp userTemp = obtainUserFormHeader(httpHeaders);

        //当没有 传递 参数的情况
        if(userTemp == null){
            return new ResponseEntity<SysUser>(HttpStatus.NOT_FOUND);
        }

        //尝试查找用户库是否存在
        user = sysUserMapper.getSysUser(userTemp.username);
        if (user != null) {
            if (!user.getPassword().equals(userTemp.password)) {
                //密码不匹配
                return new ResponseEntity(HttpStatus.BAD_REQUEST);
            }
            if (user.isDisabled()) {
                //禁用 403
                return new ResponseEntity(HttpStatus.FORBIDDEN);
            }
            if (user.isLocked()) {
                //锁定 423
                return new ResponseEntity(HttpStatus.LOCKED);
            }
            if (user.isExpired()) {
                //过期 428
                return new ResponseEntity(HttpStatus.PRECONDITION_REQUIRED);
            }
        } else {
            //不存在 404
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
    } catch (UnsupportedEncodingException e) {
        logger.error("", e);
        new ResponseEntity(HttpStatus.BAD_REQUEST);
    }
    logger.info("[{" + user.getUsername() + "}] login is ok");
    //成功返回json
    return user;
}


/**
 * 根据请求头获取用户名及密码
 *
 * @param httpHeaders
 * @return
 * @throws UnsupportedEncodingException
 */
private UserTemp 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");//用户名:密码
    logger.debug("login user: " + usernamePassword);
    String credentials[] = usernamePassword.split(":");
    return new UserTemp(credentials[0], credentials[1]);
}


/**
 * 解析请求过来的用户
 */
private class UserTemp {
    private String username;
    private String password;

    public UserTemp(String username, String password) {
        this.username = username;
        this.password = password;
    }
}

}
浏览器Flash插件异常,复制失败!
四、测试
Untitled.gif

五、源码下载
https://github.com/X-rapido/CAS_SSO_Record

六、参看文档
https://apereo.github.io/cas/5.2.x/installation/Rest-Authentication.html

https://apereo.github.io/cas/5.2.x/installation/Configuration-Properties.html#rest-authentication

https://blog.youkuaiyun.com/u010475041/article/details/77972605

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值