按照上篇的cas服务端的配置一样,集成shiro+pac4j,其实在1.3还是1.2shiro-cas就过期了,shiro官方也让我们集成pac4j,但是居然居然没有demo,我也是服,,。。
此篇博客将集成springboot+cas5+shiro+pac4j 集成在一起,是宝宝将近一个月的心血,还有老大的帮忙!!!!
开始我的表演:
首先是pom
<?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>com.bofeng.shiro</groupId> <artifactId>shiro-cas-pac4j</artifactId> <version>1.0.0</version> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.java.version>1.8</project.build.java.version> <logback.version>1.1.3</logback.version> <commons-lang3.version>3.4</commons-lang3.version> <guava.version>18.0</guava.version> <fastjson.version>1.2.8</fastjson.version> <commons-io.version>2.4</commons-io.version> <commons-codec.version>1.10</commons-codec.version> <shiro.version>1.4.0</shiro.version> <buji.version>3.0.0</buji.version> <pac4j.version>2.1.0</pac4j.version> <cas-client.version>3.4.1</cas-client.version> <log4jdbc.remix.version>0.2.7</log4jdbc.remix.version> <slf4j.version>1.7.21</slf4j.version> <logback.version>1.1.7</logback.version> <lombok.version>1.16.20</lombok.version> </properties> <dependencies> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>io.buji</groupId> <artifactId>buji-pac4j</artifactId> <version>${buji.version}</version> </dependency> <dependency> <groupId>org.pac4j</groupId> <artifactId>pac4j-cas</artifactId> <version>${pac4j.version}</version> </dependency> <dependency> <groupId>org.pac4j</groupId> <artifactId>pac4j-jwt</artifactId> <version>${pac4j.version}</version> </dependency> <dependency> <groupId>org.pac4j</groupId> <artifactId>pac4j-http</artifactId> <version>${pac4j.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>${logback.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <executable>true</executable> </configuration> </plugin> </plugins> </build> </project>
然后是shiro 的认证,由于集成了pac4j,所以我们只要关心权限
的控制就可以了
@Slf4j public class ShiroPac4jRealm extends Pac4jRealm { @Override protected AuthorizationInfo doGetAuthorizationInfo(final PrincipalCollection principals) { Object user = super.getAvailablePrincipal(principals); log.info("登录用户:{}", user); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); List<String> permissions = new ArrayList<String>(); permissions.add("user:info"); simpleAuthorizationInfo.addStringPermissions(permissions); return simpleAuthorizationInfo; } }
shiro这里不详解,只说集成,shiro的配置如下
package com.bofeng.shiro.config; import io.buji.pac4j.filter.CallbackFilter; import io.buji.pac4j.filter.SecurityFilter; import io.buji.pac4j.subject.Pac4jSubjectFactory; import org.apache.shiro.mgt.SubjectFactory; import org.apache.shiro.realm.Realm; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.spring.web.config.AbstractShiroWebFilterConfiguration; import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.jasig.cas.client.session.SingleSignOutFilter; import org.jasig.cas.client.session.SingleSignOutHttpSessionListener; import org.pac4j.cas.client.CasClient; import org.pac4j.cas.client.rest.CasRestFormClient; import org.pac4j.cas.config.CasConfiguration; import org.pac4j.cas.config.CasProtocol; import org.pac4j.core.client.Clients; import org.pac4j.core.config.Config; import org.pac4j.core.matching.PathMatcher; import org.pac4j.http.client.direct.ParameterClient; import org.pac4j.jwt.config.encryption.SecretEncryptionConfiguration; import org.pac4j.jwt.config.signature.SecretSignatureConfiguration; import org.pac4j.jwt.credentials.authenticator.JwtAuthenticator; import org.pac4j.jwt.profile.JwtGenerator; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.web.filter.DelegatingFilterProxy; import javax.servlet.Filter; import java.util.HashMap; import java.util.Map; @Configuration public class ShiroConfiguration extends AbstractShiroWebFilterConfiguration { @Value("#{ @environment['cas.prefixUrl'] ?: null }") private String prefixUrl; @Value("#{ @environment['cas.loginUrl'] ?: null }") private String casLoginUrl; @Value("#{ @environment['cas.callbackUrl'] ?: null }") private String callbackUrl; //jwt秘钥 @Value("${jwt.salt}") private String salt; /** * JWT Token 生成器,对CommonProfile生成然后每次携带token访问 * * @return */ @SuppressWarnings("rawtypes") @Bean protected JwtGenerator jwtGenerator() { return new JwtGenerator(new SecretSignatureConfiguration(salt), new SecretEncryptionConfiguration(salt)); } @Bean protected JwtAuthenticator jwtAuthenticator() { JwtAuthenticator jwtAuthenticator = new JwtAuthenticator(); jwtAuthenticator.addSignatureConfiguration(new SecretSignatureConfiguration(salt)); jwtAuthenticator.addEncryptionConfiguration(new SecretEncryptionConfiguration(salt)); return jwtAuthenticator; } /** * cas的基本设置,包括或url等等,rest调用协议等 * * @return */ @Bean public CasConfiguration casConfiguration() { CasConfiguration casConfiguration = new CasConfiguration(casLoginUrl); casConfiguration.setProtocol(CasProtocol.CAS20); casConfiguration.setPrefixUrl(prefixUrl); return casConfiguration; } /** * 不拦截的路径 * * @return */ @Bean public PathMatcher pathMatcher() { PathMatcher pathMatcher = new PathMatcher(); pathMatcher.excludePath("/html/**"); return pathMatcher; } /** * pac4jRealm * * @return */ @Bean(name = "pac4jRealm") public Realm pac4jRealm() { return new ShiroPac4jRealm(); } /** * 通过rest接口可以获取tgt,获取service ticket,甚至可以获取CasProfile * * @return */ @Bean protected CasRestFormClient casRestFormClient(CasConfiguration casConfiguration) { CasRestFormClient casRestFormClient = new CasRestFormClient(); casRestFormClient.setConfiguration(casConfiguration); casRestFormClient.setName("rest"); return casRestFormClient; } /** * casClient * * @return */ @Bean public CasClient casClient(CasConfiguration casConfiguration) { CasClient casClient = new CasClient(); casClient.setConfiguration(casConfiguration); casClient.setCallbackUrl(callbackUrl); casClient.setName("cas"); return casClient; } /** * token校验相关 * * @return */ @Bean protected Clients clients(CasClient casClient, CasRestFormClient casRestFormClient) { //可以设置默认client Clients clients = new Clients(); //token校验器,可以用HeaderClient更安全 ParameterClient parameterClient = new ParameterClient("token", jwtAuthenticator()); parameterClient.setSupportGetRequest(true); parameterClient.setName("jwt"); //支持的client全部设置进去 clients.setClients(casClient, casRestFormClient, parameterClient); return clients; } @Bean protected Config casConfig(Clients clients) { Config config = new Config(); config.setClients(clients); return config; } /** * 由于cas代理了用户,所以必须通过cas进行创建对象 * * @return */ @Bean(name = "subjectFactory") protected SubjectFactory subjectFactory() { return new Pac4jSubjectFactory(); } /** * 单点登出的listener * * @return */ @SuppressWarnings({"rawtypes", "unchecked"}) @Bean public ServletListenerRegistrationBean<?> singleSignOutHttpSessionListener() { ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean(); bean.setListener(new SingleSignOutHttpSessionListener()); bean.setEnabled(true); return bean; } /** * 单点登出filter * * @return */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public FilterRegistrationBean singleSignOutFilter() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setName("singleSignOutFilter"); SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter(); singleSignOutFilter.setCasServerUrlPrefix(prefixUrl); singleSignOutFilter.setIgnoreInitConfiguration(true); bean.setFilter(singleSignOutFilter); bean.addUrlPatterns("/*"); bean.setEnabled(true); return bean; } @Bean(name = "securityManager") public DefaultWebSecurityManager securityManager(Realm pac4jRealm, SubjectFactory subjectFactory) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); defaultWebSecurityManager.setRealm(pac4jRealm); defaultWebSecurityManager.setSubjectFactory(subjectFactory); return defaultWebSecurityManager; } @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new DelegatingFilterProxy("shiroFilter")); filterRegistrationBean.addInitParameter("targetFilterLifecycle", "true"); filterRegistrationBean.setEnabled(true); filterRegistrationBean.addUrlPatterns("/*"); return filterRegistrationBean; } @Bean(name = "shiroFilter") protected ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager, Config config) { ShiroFilterFactoryBean filterFactoryBean = super.shiroFilterFactoryBean(); filterFactoryBean.setSecurityManager(securityManager); //过滤器设置 Map<String, Filter> filters = new HashMap<String, Filter>(); SecurityFilter securityFilter = new SecurityFilter(); securityFilter.setClients("cas,rest,jwt"); securityFilter.setConfig(config); filters.put("casSecurityFilter", securityFilter); CallbackFilter callbackFilter = new CallbackFilter(); callbackFilter.setConfig(config); filters.put("callbackFilter", callbackFilter); filterFactoryBean.setFilters(filters); return filterFactoryBean; } @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition(); definition.addPathDefinition("/callback", "callbackFilter"); definition.addPathDefinition("/you", "anon"); definition.addPathDefinition("/**", "casSecurityFilter"); return definition; } /** * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能 * * @return */ @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } /** * 开启 shiro aop注解支持 * * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor(); aasa.setSecurityManager(securityManager); return aasa; } }
一个配置类
package com.bofeng.shiro.config; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.UnauthorizedException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class ShiroExceptionHandler { // @ExceptionHandler(value = {AuthorizationException.class}) // public Map<String, Object> authorizationExceptionHandler(HttpServletRequest request, Exception e) { // return noPermissionResult(); // } @ExceptionHandler(value = {UnauthorizedException.class}) public Map<String, Object> unauthorizedExceptionHandler(HttpServletRequest request, Exception e) { return noPermissionResult(); } private Map<String, Object> noPermissionResult() { Map<String, Object> result = new HashMap<String, Object>() { private static final long serialVersionUID = 1L; { put("errcode", 0); put("errmsg", "暂无权限"); } }; return result; } }
启动类顺便也贴出来了
package com.bofeng.shiro; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @RequiresPermissions(value = "role:edit") @GetMapping(value = "/roles/{id}") public String put(){ return "允许修改角色"; } @RequiresPermissions(value = "user:info") @GetMapping(value = "/users/{id}") public PrincipalCollection getUserById() { return SecurityUtils.getSubject().getPrincipals(); } @GetMapping(value = "/you") public String you(){ return "you you 不需要权限"; } }
最重要的yml文件
server: port: 8083 spring: http: encoding: charset: UTF-8 enabled: true force: true mail: default-encoding: UTF-8 messages: encoding: UTF-8 casServerUrlPrefix: https://passport.sso.com:9898/cas cas: prefixUrl: https://passport.sso.com:9898/cas loginUrl: ${cas.prefixUrl}/login logoutUrl: ${cas.prefixUrl}/logout serviceUrl: http://www.casclient2.com:${server.port} callbackUrl: ${cas.serviceUrl}/callback jwt: salt: cas debug: true
配置什么的你们看自己需求改,host别说不会
到这里Springboot的客户端就集成好了,如果还是有问题的话Q845896876交流
如果这篇博客帮你解决了问题,那么那么请给宝宝一点动力
源码提供给大家参考 请分开tomcat部署 https://download.csdn.net/download/weixin_39819191/10422417
验证码,自定义登录页面>https://blog.csdn.net/u010588262/article/details/80014083