CAS单点登录-自定义认证之Shiro、Rest(六)
来源:互联网 发布:大数据促进旅游产业 编辑:程序博客网 时间:2024/06/06 13:03
CAS单点登录-自定义认证之Shiro、Rest(六)
注意:单点登录版本为cas-5.1.3
若需要上个版本代码,可以点击下载:
这章即将讲解cas服务端集成shiro认证、Rest认证
上一章讲了自定认证之jdbc 已经解决了很多需求上的问题,但这远远不够,因为需求总是变态的,所以我们要时刻准备着
犹如:
- 公司老程序员多,用目前使用成熟的技术吧
- 公司数据安全性有要求,cas不允许连到我的账号库,哦,给我写个接口总可以吧
Shiro认证
接下来不得不分析一下shiro的需求量:
- 框架使用shiro鉴权 ★★★★☆
- 熟悉shiro的比较多 ★★★★★
- 相对于来说轻量级 ★★☆☆☆
当然了使用shiro的公司还是非常的多,听说包括spring的官网也是用shiro的,所以在cas中集成shiro进行鉴权,把老系统的配置直接拿来用,那再好不过了。
pom.xml
添加maven依赖
<dependency> <groupId>org.apereo.cas</groupId> <artifactId>cas-server-support-generic</artifactId> <version>${cas.version}</version></dependency>
加了依赖即将支持三种校验方式,包括文件存储用户校验器、拒绝用户校验器、shiro校验器
若对Whitelist(文件校验白名单)、Blacklist(黑名单)机制、配置了解或者有需求疑问感兴趣可以联系博主,这些将不讲解,但附上配置图
cas系统配置
# Shiro Authentication 开始#允许登录的用户,必须要有以下权限,否则拒绝,多个逗号隔开cas.authn.shiro.requiredPermissions=staff#允许登录的用户,必须要有以下权限,否则拒绝,多个逗号隔开cas.authn.shiro.requiredRoles=admin#shir配置文件位置cas.authn.shiro.config.location=classpath:shiro.ini#shiro name 唯一cas.authn.shiro.name=cas-shiro# 与Query Authentication一致的加密策略cas.authn.shiro.passwordEncoder.type=DEFAULT# cas.authn.shiro.passwordEncoder.characterEncoding=UTF-8cas.authn.shiro.passwordEncoder.encodingAlgorithm=MD5# Shiro Authentication 结束
shiro.ini:
[main]cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManagersecurityManager.cacheManager = $cacheManager[users]#密码123admin = 202cb962ac59075b964b07152d234b70, admin#不可登录,因为配置了需要角色admin#密码123456test = e10adc3949ba59abbe56e057f20f883e, developer[roles]admin = system,admin,staff,superuser:*developer = commit:*
这个文件就不多说了,主要是看shiro的配置情况,包括可以自定义用户存储策略,校验realm
,从侧面来说只需要配置鉴权部分即可
注意: cas-shiro只做Subject.login();
另外一个角度说,只做鉴权,不做其他退出之类的,所以在这里filter之类的鉴权器是无作用的跟不用说urls选项的匹配。
测试
尝试登录:
- admin/123 成功
- test/123456 失败(没有权限)
Rest 认证
由于架构或公司政策等原因,不得不使用接口来打通数据的问题。
那问题来了:
问:什么是Rest认证?
答:通过数据接口对用户进行认证
问:cas又是怎么做的?
答:通过请求接口,返回固定格式,进行对密码匹配,判断用户是否合法
问:什么场景下用rest认证?用户数据存在远端、不允许cas直接访问帐号数据、cas不希望你知道帐号数据的表结构、存储方式可能目前不满足
配置
application.properties
#REST 认证开始#请求远程调用接口cas.authn.rest.uri=http://localhost:8881/login#加密策略cas.authn.rest.passwordEncoder.type=DEFAULTcas.authn.rest.passwordEncoder.characterEncoding=UTF-8#加密算法cas.authn.rest.passwordEncoder.encodingAlgorithm=MD5#REST 结束
当用户点击登录后,cas会发送post请求到
http://localhost:8881/login
并且把用户信息以”用户名:密码”进行Base64编码放在authorization请求头中
若输入用户名密码为:admin/123
那么请求头包括:
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过期;其他登录失败
客户端校验Demo
SysUser.java
/* * 版权所有.(c)2008-2017. 卡尔科技工作室 */package com.carl.auth.sso.rest.client.bean;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 Carl * @date 2017/9/14 * @since JDK1.7 */public class SysUser { @JsonProperty("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 @NotNull private String password; @JsonIgnore //用户是否不可用 private boolean disable = false; @JsonIgnore //用户是否过期 private boolean expired = false; @JsonIgnore //是否锁定 private boolean locked = false; public boolean isLocked() { return locked; } public SysUser setLocked(boolean locked) { this.locked = locked; return this; } public boolean isDisable() { return disable; } public SysUser setDisable(boolean disable) { this.disable = disable; return this; } public boolean isExpired() { return expired; } public SysUser setExpired(boolean expired) { this.expired = expired; return this; } public String getPassword() { return password; } public SysUser setPassword(String password) { this.password = password; return this; } public String getUsername() { return username; } public SysUser setUsername(String username) { this.username = username; return this; } public String getClazz() { return clazz; } public Map<String, Object> getAttributes() { return attributes; } public SysUser setAttributes(Map<String, Object> attributes) { this.attributes = attributes; return this; } @JsonIgnore public SysUser addAttribute(String key, Object val) { getAttributes().put(key, val); return this; }}
而上面的属性,必须跟@class
的实现一一对应,如attributes 就是返回属性给对接的客户端,有必要的信息必须返回给cas,cas会进行二次过滤,而二次过滤是属于多属性返回的内容,后面的章节会说明白哦
AuthUserController.java
/* * 版权所有.(c)2008-2017. 卡尔科技工作室 */package com.carl.auth.sso.rest.client.controller;import com.carl.auth.sso.rest.client.bean.SysUser;import com.carl.auth.sso.rest.client.service.UserRepertory;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.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestHeader;import org.springframework.web.bind.annotation.RestController;import java.io.UnsupportedEncodingException;/** * @author Carl * @date 2017/9/14 * @since JDK1.7 */@RestControllerpublic class AuthUserController { private static final Logger LOGGER = LoggerFactory.getLogger(AuthUserController.class); @Autowired private UserRepertory userRepertory; /** * 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 */ @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); //尝试查找用户库是否存在 user = userRepertory.getUser(userTemp.username); if (user != null) { if (!user.getPassword().equals(userTemp.password)) { //密码不匹配 return new ResponseEntity(HttpStatus.BAD_REQUEST); } if (user.isDisable()) { //禁用 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("[{}] login is ok", user.getUsername()); //成功返回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(用户名:密码) 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; } }}
这段代码核心是实现cas明确要求的返回值,如果敢兴趣,请仔细看注解
若尝试用户rest-locked/admin
结果如下
总结
- shiro的使用率及集成
- rest的应用场景及集成
cas的认证方式中,最常见三种校验方式:
- 数据库查询(上一章)
- shiro集成验证(本章)
- 远程rest认证(本章)
相信很多人对自定义校验器
非常感兴趣,例如验证码登录、扫码登录等等,那么这些再后面再继续说
因为验证码登录必须先把界面调整,这是主题的范畴,回过头再讲自定义。
下载本章代码:
注意:
由于版本5.1.3是shiro.ini配置在classpath下会从临时文件中加载,有bug,希望在5.1.4或者5.1.5进行解决,那么如果在5.1.3希望用shiro,配置在其他系统盘绝对路径即可
下载代码后注意查看README.md
用户:
作者联系方式
如果技术的交流或者疑问可以联系或者提出issue。
邮箱:huang.wenbin@foxmail.com
QQ: 756884434 (请注明:SSO-CSDN)
- CAS单点登录-自定义认证之Shiro、Rest(六)
- CAS单点登录-自定义认证之JDBC(五)
- CAS单点登录-自定义认证之重写Credential(十五)
- Cas之5.2.x版本单点登录自定义REST认证-yellowcong
- shiro-cas 单点登录
- Shiro之CAS单点登录-yellowcong
- Cas单点登录(整合shiro版本)
- Shiro & CAS 实现单点登录
- Shiro & CAS 实现单点登录
- shiro 集成cas单点登录
- CAS 实现单点登录(SSO)数据库查询认证机制-自定义编码方式(四)
- 利用CAS之SSO模块实现单点登录认证
- CAS单点登录源码解析之【用户认证】
- 4、CAS单点登录源码解析之【用户认证】
- SSO之CAS+LDAP实现单点登录认证
- 基于CAS实现单点登录(SSO):CAS+LDAP实现单点登录认证
- shiro结合cas实现单点登录
- spring + shiro + cas 实现sso单点登录
- 深入浅出,Handler机制外科手术式的剖析(ThreadLocal,Looper,MessageQueen,Message)(下)
- springmvc中,在业务控制方法中,收集数组参数,收集List集合包含javabean
- mysql5.7.18 更改密码是出现 Unknown column 'password' in 'field list'错误
- 莫比乌斯进阶:bzoj 2693 jzptab(Mobius)
- Myeclipse 10 激活详解过程
- CAS单点登录-自定义认证之Shiro、Rest(六)
- iOS【Undefined symbols for architecture i386: 错误的解决办法】
- centos6和centos7防火墙的关闭
- 第二章 算法基础
- Fork/Join 框架 详解
- ffmpeg.exe工具的基本命令
- Android 语音播报
- 取数比最大博弈题:判断是否必胜
- 如何用MATLAB读取csv文件