Jfinal+Shiro+Pac4j+Cas+Redis jfinal最强全家桶集成方案

Jifnal+Shiro+Pac4j+Cas+Redis

简介

         公司以前使用了Jifnal做了一个基础后台管理系统,主要使用了Jifnal+Shiro进行开发.随后交由我
    进行后续的升级以及功能的完善.由于jfinal和shiro集成的时候默认使用的Ehcache对集群部署以
    及分布式部署会出问题,所以替换为Redis,并对 Session管理重写支持Redis缓存存储.

         随着需求不断升级,项目需要支持SSO单点登录.由于Jifnal本身在集成单点框架上资料非常少无法
 入手,在咨询官方作者 后,答复是可以自己写一个类似的功能代码量也不大.但是考虑到作为公司
 一个基础平台在后续如果需要集成或者对接其 他公司系统时候,无疑是灾难.经过研究以及网上

搜集资料后整理成为一个最强全家桶方案.

CAS

https://github.com/apereo/cas

版本:
服务端 5.3.x
客户端 3.5.0

cas服务端搭建不在赘述

具体搭建传送门 : https://www.cnblogs.com/ll409546297/p/10410972.html

Pac4J

pac4j 是一个 java 的安全引擎.

在一套标准的 interface 下,

提供了很多种认证机制: form 表单登录, JWS, cas, OAuth 等等.

提供了很多收授权和权限检查机制: role/permissions, CORS, CSRF, HTTP Security headers

提供了跟很多框架的集成方式: springboot, play, shiro, spring security

这些认证方式都是可插拔的, 你可以同时使用其中的一种或几种.

源码 https://github.com/bujiio/buji-pac4j

官方Demo https://github.com/pac4j/buji-pac4j-demo

版本
io-buji 4.1.1
pac4j-core 3.9.0

友情提示

官方demo中的cas启动访问会报500

主要原因是没有配置callbackFilter

我追加的配置:

callbackFilter=io.buji.pac4j.filter.CallbackFilter
callbackFilter.config = $config
callbackFilter.defaultUrl = http://x.x.x.x:port
callbackFilter.defaultClient = $clients

defaultUrl地址是客户端地址,这个可以不配

集成配置

最新版本的Pac4j的包使用Java11 编译的如果项目使用的JDK 版本低就很难受再次强调我用的版本
io-buji 4.1.1,pac4j-core 3.9.0

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <display-name>JFinal</display-name>

    <listener>
        <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
    </listener>

    <filter>
        <filter-name>shiro</filter-name>
        <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>shiro</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 配置JFinal拦截器 -->
    <filter>
        <filter-name>jfinal</filter-name>
        <filter-class>com.jfinal.core.JFinalFilter</filter-class>
        <init-param>
            <param-name>configClass</param-name>
            <param-value>com.ljph.seckill.common.MyConfig</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>jfinal</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

shiro.ini

[main]
#pac4j clients
clients = org.pac4j.core.client.Clients
clients.callbackUrl = http://192.168.1.185:8090/callback
clients.clients =  $casClient,$headerClient

#pac4j session
sessionStore=com.bz.platform.common.ext.shiro.cas.MyShiroSessionStore

#pac4j config
config = org.pac4j.core.config.Config
config.clients = $clients
config.sessionStore=$sessionStore

#pac4j realm
pac4jRealm = com.bz.platform.common.ext.shiro.realm.MyPac4jRealm
#io.buji.pac4j.realm.Pac4jRealm
#是否开启缓存
pac4jRealm.cachingEnabled=true
pac4jRealm.authenticationCacheName=Pac4jRealm_
#认证缓存开关 在没有解决cas服务端退出可以清除客户端shiro缓存的前提下千万不要开启
#否则在服务端退出后重新登录并访问客户端会取缓存数据进行校验出现Pac4jToken认证异常
pac4jRealm.authenticationCachingEnabled=false
#授权缓存开关
pac4jRealm.authorizationCachingEnabled=true

#pac4j subject
pac4jSubjectFactory = io.buji.pac4j.subject.Pac4jSubjectFactory
securityManager.subjectFactory = $pac4jSubjectFactory

#logout handler
casLogoutHandler=org.pac4j.core.logout.handler.DefaultLogoutHandler
casLogoutHandler.destroySession=true

#cas config
casConfig = org.pac4j.cas.config.CasConfiguration
casConfig.loginUrl = http://192.168.1.110:8080/cas/login
casConfig.prefixUrl = http://192.168.1.110:8080/cas/
casConfig.logoutHandler=$casLogoutHandler

#parameter client
parameterClient = org.pac4j.http.client.direct.ParameterClient
parameterClient.parameterName = X-Token
parameterClient.authenticator = $jwtAuthenticator
parameterClient.supportGetRequest = true
parameterClient.supportPostRequest = true

# X-Token为请求中header的参数key
# authc是token中开头主动添加的字符 因为在请求token校验时候会检验token是否以指定的字符串开头的
headerClient=org.pac4j.http.client.direct.HeaderClient
headerClient.headerName = X-Token
headerClient.prefixHeader = authc
headerClient.authenticator = $jwtAuthenticator

#cas client
casClient=com.bz.platform.common.ext.shiro.cas.MyCasClient
#org.pac4j.cas.client.CasClient
casClient.configuration = $casConfig

#RedisCache
redisCacheManager = com.bz.platform.common.redis.cache.RedisCacheManager
securityManager.cacheManager = $redisCacheManager

#redis管理session
sessionDAO = com.bz.platform.common.redis.session.OnlineSessionDao
sessionManager = com.bz.platform.common.redis.session.MyWebSessionManager
sessionDAO.activeSessionsCacheName = shiro-activeSessionCache
sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager = $sessionManager

#session监听 (主要用于监听session 创建和删除,暂时不用关注)
sessionListener =com.bz.platform.common.redis.session.ShiroSessionListener
securityManager.sessionManager.sessionListeners =$sessionListener
sessionManager.sessionValidationSchedulerEnabled = false
sessionManager.sessionValidationInterval=5000

# 超时时间60*60*1000  3600000  如果不设置默认30min
securityManager.sessionManager.globalSessionTimeout = 1800000

#在线用户管理 客户端数量限制不建议加在此处
kickout=com.bz.platform.common.ext.filter.KickoutSessionControlFilter
kickout.cacheManager=$redisCacheManager
kickout.sessionManager=$sessionManager
kickout.kickoutUrl=/index
#一个终端类型只允许登录一次
kickout.maxSession=1

signingConfig = org.pac4j.jwt.config.signature.SecretSignatureConfiguration
signingConfig.secret = 12345678901234567890123456789012
encryptionConfig = org.pac4j.jwt.config.encryption.SecretEncryptionConfiguration
encryptionConfig.secret = 12345678901234567890123456789012

jwtAuthenticator = org.pac4j.jwt.credentials.authenticator.JwtAuthenticator
jwtAuthenticator.signatureConfiguration = $signingConfig
jwtAuthenticator.encryptionConfiguration = $encryptionConfig


#authFilter
casFilter = io.buji.pac4j.filter.SecurityFilter
casFilter.config = $config
casFilter.clients = MyCasClient

#callback
callbackFilter=io.buji.pac4j.filter.CallbackFilter
callbackFilter.config = $config
callbackFilter.defaultUrl = http://192.168.1.185:8090/
#callbackFilter.defaultClient = $clients

#pac4j logout Filter
pac4jLogout = io.buji.pac4j.filter.LogoutFilter
pac4jLogout.config = $config
pac4jLogout.localLogout = true
pac4jLogout.centralLogout = true
pac4jLogout.defaultUrl=http://192.168.1.185:8090/callback?client_name=CasClient
pac4jLogout.logoutUrlPattern = http://192.168.1.185:8090/.*

#jwt filter
jwtSecurityFilter = io.buji.pac4j.filter.SecurityFilter
jwtSecurityFilter.config = $config
jwtSecurityFilter.clients = HeaderClient
[urls]
#首次进入/访问项目时进行cas认证过滤
/ = casFilter
#cas认证通过后系统回调
/callback = callbackFilter
#登出系统过滤
/pac4jLogout = pac4jLogout
#jwt过滤校验(所有请求都进行校验没有携带token或者token错误)
/** = jwtSecurityFilter
#kickout先暂停 等待cas服务端修改完毕在考虑是否继续存在
/** = kickout

重写Seesion以及sessionManager主要目的是为了缓存在Redis中这块可以不要不影响系统正常使用

引用文本

POM.xml
再次强调我只列了核心包,如果缺包的话jfinal就不说了 按官方的来,Shiro和cas已经随Pac4j引入其他的包可以参考buji-pac4j-demo官方demo 不过demo的jar下载有时候会比较慢

没有贴全pom是因为项目分了好几个moudles 所以没有全部贴

<properties>
     <pac4jVersion>3.9.0</pac4jVersion>
     <bujiVersion>4.1.1</bujiVersion>
  </properties>
<!-- pac4j-core -->
        <dependency>
            <groupId>org.pac4j</groupId>
            <artifactId>pac4j-core</artifactId>
        </dependency>

        <!--cas  pac4j 相关jar-->
        <dependency>
            <groupId>io.buji</groupId>
            <artifactId>buji-pac4j</artifactId>
            <version>${bujiVersion}</version>
            <exclusions>
                <exclusion>
                    <artifactId>org.pac4j</artifactId>
                    <groupId>pac4j-core</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.pac4j</groupId>
            <artifactId>pac4j-core</artifactId>
            <version>${pac4jVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.pac4j</groupId>
            <artifactId>pac4j-cas</artifactId>
            <version>${pac4jVersion}</version>
            <exclusions>
                <exclusion>
                    <artifactId>org.pac4j</artifactId>
                    <groupId>pac4j-core</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.pac4j</groupId>
            <artifactId>pac4j-jwt</artifactId>
            <version>${pac4jVersion}</version>
            <exclusions>
                <exclusion>
                    <artifactId>org.pac4j</artifactId>
                    <groupId>pac4j-core</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.pac4j</groupId>
            <artifactId>pac4j-http</artifactId>
            <version>${pac4jVersion}</version>
            <exclusions>
                <exclusion>
                    <artifactId>org.pac4j</artifactId>
                    <groupId>pac4j-core</groupId>
                </exclusion>
            </exclusions>
        </dependency>

基础的配置引入已经基本完毕了.接下来就是JWTtoken的生成

JWT Token

public void index() {
        try {
            // 获取用户身份
            Pac4jPrincipal p = SecurityUtils.getSubject().getPrincipals().oneByType(Pac4jPrincipal.class);
            CommonProfile profile = p.getProfile();
			// 这是取出cas服务端返回的用户数据
            Map profileMap=profile.getAttributes();
            // 生成token
            final JwtGenerator generator = new JwtGenerator(new SecretSignatureConfiguration("12345678901234567890123456789012"));
            String token = null;
            final PrincipalCollection col = SecurityUtils.getSubject().getPrincipals();
            if (col != null) {
                final Pac4jPrincipal principal = col.oneByType(Pac4jPrincipal.class);
                if (principal != null) {
                    token = generator.generate(principal.getProfile());
                }
            }
            // 因为我们是前后端分离前端用的vue所以token传到前端是个问题
            // 开发阶段可以使用下面的方式先把token传过去,正式部署阶段因为前后端打包放一起可以使用Cookie存储
            // 将签发的 JWT token 设置到 HttpServletResponse 的 Header中,并重写向vue前端页面
            getResponse().setHeader("token", token);
            //getResponse().sendRedirect("http://192.168.0.41:8088/#/stats/casindex");
            getResponse().sendRedirect("http://192.168.200.185:9527/#/"+"?X-Token=authc"+token);
        } catch (Exception e) {
            e.getStackTrace();
        }
        renderNull();
    }

到此基本已经集成完毕并且可以使用了,后面我抽时间继续补充完善.后续如果大家需求大的话我考虑吧上述的一些配置或者类整理传到git上,先这样吧 有问题可以先留言.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JFinal是一款基于Java的轻量级Web开发框架,而Shiro是一个强大且易用的Java安全框架。集成JFinalShiro可以为你的应用程序提供更好的安全性和权限控制。 要在JFinal集成Shiro,你需要进行以下步骤: 1. 添加Shiro依赖:在你的项目中添加Shiro的依赖,可以通过Maven或者手动下载jar包的方式引入。 2. 创建Shiro配置类:创建一个继承自JFinalJFinalConfig类,并重写configConstant()和configInterceptor()方法。在configConstant()方法中配置Shiro的相关参数,如设置登录页面、未授权页面等。在configInterceptor()方法中添加Shiro的拦截器,用于实现权限控制。 3. 创建ShiroRealm类:创建一个继承自org.apache.shiro.realm.AuthorizingRealm的类,用于实现用户认证和授权逻辑。在该类中,你需要重写doGetAuthenticationInfo()方法用于用户认证,以及重写doGetAuthorizationInfo()方法用于用户授权。 4. 配置ShiroFilter:在JFinal的configRoute()方法中配置ShiroFilter,用于拦截请求并进行权限验证。你可以通过配置URL的匹配规则和相应的权限要求来实现不同页面的权限控制。 5. 配置登录和注销功能:在JFinal的Controller中添加登录和注销的处理逻辑,包括用户登录验证、生成和保存用户的身份信息等。 6. 配置权限注解:使用Shiro的注解来标记需要进行权限验证的方法或类,以实现细粒度的权限控制。 以上是集成JFinalShiro的基本步骤,你可以根据具体需求进行更详细的配置和扩展。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值