本文共 6576 字,大约阅读时间需要 21 分钟。
原文地址,转载请注明出处: ©
我们之前在cas服务端整合了shiro,在shirorealm中通过查询数据库获取用户信息和角色等信息,如果都是内部服务,将从数据库中获取信息改为通过调用接口获取信息就可以了,这也是一种方式,这里是演示一下官网的配置。
cas服务端通过调用其他服务接口,将用户名和密码传过去进行认证。这就是rest认证。
在不允许cas服务直接访问账号数据库的时候,这个时候就需要用到Rest认证。
节点 | 服务名 |
---|---|
app1.cas.com:8081 | CAS客户端(只是用来测试单点登录用的,代码参考之前博客) |
CAS服务端 | |
rest.cas.com:8083 | rest-client(认证服务) |
当用户点击登录后,cas会发送post请求到http://rest.cas.com:8083/login
并且把用户信息以"用户名:密码"
进行Base64编码放在authorization请求头中。
org.apereo.cas cas-server-support-rest-authentication ${cas.version}
cas.authn.rest.uri=http://rest.cas.com:8083/login#如果密码有加密,打开下面配置,我的是明文#cas.authn.rest.passwordEncoder.type=DEFAULT#cas.authn.rest.passwordEncoder.characterEncoding=UTF-8#cas.authn.rest.passwordEncoder.encodingAlgorithm=MD5
rest-client为一个传统的ssm项目,提供一个rest接口,接口遵循上面介绍的规则。这里这展示接口相关代码。
package com.wangsaichao.cas.dao.entity;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;/** * @author: wangsaichao * @date: 2018/8/9 * @description: cas-rest返回cas服务端信息 */public class SysUser { @JsonProperty("id") @NotNull private String username; /** * 需要返回实现org.apereo.cas.authentication.principal.Principal的类名接口 */ @JsonProperty("@class") private String clazz = "org.apereo.cas.authentication.principal.SimplePrincipal"; @JsonProperty("attributes") private Mapattributes = new HashMap<>(); @JsonIgnore @NotNull private String password; /** * 用户状态,根据状态判断是否可用 */ @JsonIgnore private String state; 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 getAttributes() { return attributes; } public void setAttributes(Map attributes) { this.attributes = attributes; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getState() { return state; } public void setState(String state) { this.state = state; } @JsonIgnore public SysUser addAttribute(String key, Object val) { getAttributes().put(key, val); return this; }}
package com.wangsaichao.cas.controller;import com.wangsaichao.cas.dao.entity.SysUser;import com.wangsaichao.cas.service.UserService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;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.RequestHeader;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.io.UnsupportedEncodingException;/** * @author: wangsaichao * @date: 2018/8/1 * @description: 对比用户信息 */@RestControllerpublic class UserController { private static final Logger logger = LoggerFactory.getLogger(UserController.class); @Autowired private UserService userService; /** * 1. cas 服务端会通过post请求,并且把用户信息以"用户名:密码"进行Base64编码放在authorization请求头中 * 2. 返回200状态码并且格式为{"@class":"org.apereo.cas.authentication.principal.SimplePrincipal","id":"casuser","attributes":{}} 是成功的 * 2. 返回状态码403用户不可用;404账号不存在;423账户被锁定;428过期;其他登录失败 * @param httpHeaders * @return */ @RequestMapping("/login") public Object login(@RequestHeader HttpHeaders httpHeaders){ logger.info("开始验证服务"); SysUser user = null; try { UserTemp userTemp = obtainUserFormHeader(httpHeaders); //尝试查找用户库是否存在 user = userService.selectUser(userTemp.username); if (user != null) { if (!user.getPassword().equals(userTemp.password)) { //密码不匹配 return new ResponseEntity(HttpStatus.BAD_REQUEST); } if (!"0".equals(user.getState())) { //用户已锁定 return new ResponseEntity(HttpStatus.LOCKED); } } else { //不存在 404 return new ResponseEntity(HttpStatus.NOT_FOUND); } } catch (UnsupportedEncodingException e) { logger.error("用户认证错误", e); new ResponseEntity(HttpStatus.BAD_REQUEST); } //成功返回json return user; } /** * 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. * @param httpHeaders * @return * @throws UnsupportedEncodingException */ private UserTemp obtainUserFormHeader(HttpHeaders httpHeaders) throws UnsupportedEncodingException { //cas服务端会通过把用户信息放在请求头authorization中,并且通过Basic认证方式加密 String authorization = httpHeaders.getFirst("authorization"); 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 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; } }}
先使用admin登录,之后状态改为锁定,再次登录。