您的位置 首页 java

pac4j – Java 权限引擎

什么是PAC4J?

pac4j是一个简单而强大的安全引擎,用于 java 对用户进行身份验证、获取其配置文件和管理授权,以确保web应用程序安全。它提供了一套完整的概念和组件。它基于Java 8,并在Apache 2许可下使用。它可用于大多数框架/工具和支持大多数认证/授权机制。

已经集成可用的场景

J2E • Spring Web MVC (Spring Boot) • Spring Security (Spring Boot) • Apache Shiro

Play 2.x • Vertx • Spark Java • Ratpack • Undertow

CAS server • JAX-RS • Dropwizard • Apache Knox • Jooby

身份验证机制

OAuth (Facebook, Twitter, Google…) – SAML – CAS – OpenID Connect – HTTP – OpenID – Google App Engine – Kerberos (SPNEGO/Negotiate)

LDAP – SQL – JWT – MongoDB – CouchDB – IP address – REST API

授权机制

Roles/permissions – Anonymous/remember-me/(fully) authenticated – Profile type, attribute

CORS – CSRF – Security headers – IP address, HTTP method

PAC4J基本上基于jdk1.8的环境,由于公司电脑的jdk是1.7,这里就简单的集成CAS就行,其他的认证方式等回家再写,家里的电脑jdk是1.8的。

项目结构

pom .xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="" xmlns:xsi=""
 xsi:schemaLocation=" ">
 <modelVersion>4.0.0</modelVersion>
 <groupId>org.ikane</groupId>
 <artifactId>demo</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>
 <name>spring-boot-pac4j-demo</name>
 <description>Spring-boot PAC4J DEMO</description>
 <parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>1.2.8.RELEASE</version>
 <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <java.version>1.7</java.version>
 </properties>
 <dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-thymeleaf</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
 <groupId>org.thymeleaf.extras</groupId>
 <artifactId>thymeleaf-extras-springsecurity4</artifactId>
 <version>2.1.2.RELEASE</version>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-security</artifactId>
 </dependency>
 <dependency>
 <groupId>org.pac4j</groupId>
 <artifactId>spring-security-pac4j</artifactId>
 <version>1.4.1</version>
 <exclusions>
 <exclusion>
 <groupId>org.springframework.security</groupId>
 <artifactId>spring-security-web</artifactId>
 </exclusion>
 <exclusion>
 <groupId>org.springframework.security</groupId>
 <artifactId>spring-security-config</artifactId>
 </exclusion>
 </exclusions>
 </dependency>
 <dependency>
 <groupId>org.pac4j</groupId>
 <artifactId>pac4j-cas</artifactId>
 <version>1.8.5</version>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
 <scope>test</scope>
 </dependency>
 </dependencies>
 <build>
 <plugins>
 <plugin>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-maven-plugin</artifactId>
 </plugin>
 </plugins>
 </build>
</project>
 

Pac4jConfig.java

package org.ikane;
import org.ikane.security.ClientUserDetailsService;
import org.ikane.service.AccountService;
import org.pac4j.cas.client.CasClient;
import org.pac4j.core.client.Clients;
import org.pac4j.springframework.security. authentication .ClientAuthenticationProvider;
import org.springframework.beans. factory . annotation .Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation. Configuration ;
@Configuration
public class Pac4jConfig {
 public static String CAS_LOGIN_URL = "";
 @Value("${oauth.callback.url}")
 private String oauthCallbackUrl;
  @Autowired 
 AccountService  account Service;
 @Bean
 CasClient casClient() {
 return new CasClient(CAS_LOGIN_URL);
 }
 @Bean
 Clients clients() {
 return new Clients(oauthCallbackUrl, casClient());
 }
 @Bean
 ClientUserDetailsService clientUserDetailsService() {
 ClientUserDetailsService clientUserDetailsService = new ClientUserDetailsService();
 clientUserDetailsService.setAccountService(accountService);
 return clientUserDetailsService;
 }
 @Bean
 ClientAuthenticationProvider clientProvider() {
 ClientAuthenticationProvider clientAuthenticationProvider = new ClientAuthenticationProvider();
 clientAuthenticationProvider.setClients(clients());
 clientAuthenticationProvider.setUserDetailsService(clientUserDetailsService());
 return clientAuthenticationProvider;
 }
}
 

SecurityConfig.java

package org.ikane;
import org.pac4j.core.client.Clients;
import org.pac4j.springframework.security.authentication.ClientAuthenticationProvider;
import org.pac4j.springframework.security.web.ClientAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true, securedEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 @Autowired
 ApplicationContext context;
 @Autowired
 Clients clients;
 @Autowired
 ClientAuthenticationProvider clientProvider;
 @ Override 
 public void configure(WebSecurity web) throws Exception {
 web
 .ignoring()
 .antMatchers(
 "/**/*.css",
 "/**/*.png",
 "/**/*.gif",
 "/**/*.jpg",
 "/**/*.ico",
 "/**/*.js"
 );
 }
 @Override
 protected void configure(HttpSecurity http) throws Exception {
 http
 .csrf().disable()
 .authorizeRequests()
 .and()
 .formLogin()
 .loginPage("/login")
 .permitAll()
 .and()
 .logout()
 .logoutUrl("/logout")
 .logoutSuccessUrl("/")
 .permitAll()
 ;
 http.addFilterBefore(clientFilter(), UsernamePasswordAuthenticationFilter.class);
 }
 @Override
 protected void configure(AuthenticationManagerBuilder auth) throws Exception {
 super.configure(auth);
 auth.authenticationProvider(clientProvider);
 }
 ClientAuthenticationFilter clientFilter() {
 String suffixUrl="/*";
 ClientAuthenticationFilter clientAuthenticationFilter = new ClientAuthenticationFilter(suffixUrl);
 clientAuthenticationFilter.setClients(clients);
 clientAuthenticationFilter.setSessionAuthenticationStrategy(sas());
 //clientAuthenticationFilter.setAuthenticationManager((AuthenticationManager)clientProvider);
 return clientAuthenticationFilter;
 /*
 return new ClientAuthenticationFilter(
 clients: clients,
 sessionAuthenticationStrategy: sas(),
 authenticationManager: clientProvider as AuthenticationManager
 )
 */ }
 @Bean
 SessionAuthenticationStrategy sas() {
 return new SessionFixationProtectionStrategy();
 }
}
 

SpringBootPac4jDemoApplication.java

package org.ikane;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootPac4jDemoApplication {
 public static void main(String[] args) {
 SpringApplication.run(SpringBootPac4jDemoApplication.class, args);
 }
}
 

ThymeleafConfig.java

package org.ikane;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect;
@Configuration
public class ThymeleafConfig {
 @Bean
 public SpringSecurityDialect springSecurityDialect() {
 return new SpringSecurityDialect();
 }
}
 

IndexController.java

package org.ikane.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
class IndexController {
 @RequestMapping("/")
 @PreAuthorize("isAuthenticated()")
 public String index() {
 return "index";
 }
}
 

LoginController.java

package org.ikane.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.pac4j.cas.client.CasClient;
import org.pac4j.core.client.BaseClient;
import org.pac4j.core.client.Clients;
import org.pac4j.core.context.J2EContext;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.exception.RequiresHttpAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
 Logger logger = LoggerFactory.getLogger(LoginController.class);
 @Autowired
 private Clients clients;
 @RequestMapping("/login")
 public String login(HttpServletRequest request, HttpServletResponse response, Model model) {
 if (isAuthenticated()) {
 return "redirect:/";
 }
 final WebContext context = new J2EContext(request, response);
 //定义cas客户端
 final CasClient casClient = (CasClient) clients.findClient(CasClient.class);
 model.addAttribute("casAuthUrl", getClientLocation(casClient, context));
 return "login";
 }
 //获取客户端的链接
 public String getClientLocation(BaseClient client, WebContext context) {
 try {
 return ((CasClient)client).getRedirectAction(context, false).getLocation();
 } catch (RequiresHttpAction e) {
 e.printStackTrace();
 logger.error("error", e);
 return null;
 }
 //return client.getRedirectAction(context, false, false).getLocation();
 }
 protected boolean isAuthenticated() {
 Authentication auth = SecurityContextHolder.getContext().getAuthentication();
 return !(auth instanceof AnonymousAuthenticationToken);
 }
}
 

ClientUserDetails.java

package org.ikane.security;
import java.util. Collection ;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
class ClientUserDetails implements UserDetails {
 private static final long serialVersionUID = 6523314653561682296L;
 String username;
 String providerId;
 Collection<GrantedAuthority> authorities;
 String password;
 public ClientUserDetails() {
 // TODO Auto-generated constructor stub
 }
 public ClientUserDetails(String username, String providerId, Collection<GrantedAuthority> authorities) {
 super();
 this.username = username;
 this.providerId = providerId;
 this.authorities = authorities;
 }
 @Override
 public Collection<? extends GrantedAuthority> getAuthorities() {
 return authorities;
 }
 @Override
 public String getPassword() {
 return password;
 }
 @Override
 public String getUsername() {
 // TODO Auto-generated method stub
 return username;
 }
 @Override
 public boolean isAccountNonExpired() {
 return true;
 }
 @Override
 public boolean isAccountNonLocked() {
 return false;
 }
 @Override
 public boolean isCredentialsNonExpired() {
 return true;
 }
 @Override
 public boolean isEnabled() {
 return true;
 }
 public String getProviderId() {
 return providerId;
 }
 public void setProviderId(String providerId) {
 this.providerId = providerId;
 }
 public void setUsername(String username) {
 this.username = username;
 }
 public void setAuthorities(Collection<GrantedAuthority> authorities) {
 this.authorities = authorities;
 }
 public void setPassword(String password) {
 this.password = password;
 }
}
 

ClientUserDetailsService.java

package org.ikane.security;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.ikane.service.AccountService;
import org.pac4j.springframework.security.authentication.ClientAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public class ClientUserDetailsService implements AuthenticationUserDetailsService<ClientAuthenticationToken> {
 private AccountService accountService;
 public UserDetails loadUserDetails(final ClientAuthenticationToken token) throws UsernameNotFoundException {
 Map account = accountService.lookupAccountByProvider(token.getClientName(), token.getUserProfile().getId());
 //String username = account.containsKey("displayName") ? account.displayName : ""
 String username = "admin";
 final List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
 for (String role: token.getUserProfile().getRoles()) {
 authorities.add(new SimpleGrantedAuthority(role));
 }
 if (!account.isEmpty() && authorities.isEmpty()) {
 // default to user role
 authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
 }
 return new ClientUserDetails(username, token.getUserProfile().getId(), authorities);
 }
 public AccountService getAccountService() {
 return accountService;
 }
 public void setAccountService(AccountService accountService) {
 this.accountService = accountService;
 }
}
 

AccountService.java

package org.ikane.service;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Service;
@Service
public class AccountService {
 /**
 * @Autowired
 JdbcTemplate jdbcTemplate
 * */ public Map lookupAccountByProvider(String providerName, String providerUserId) {
 HashMap<Object,Object> map = new HashMap<>();
 /**
 * 
 List results = jdbcTemplate.query(
 "select * from account where provider = ? and provider_user_id = ?",
 [providerName, providerUserId] as Object[],
 new GenericRowMapper()
 )
 if (results.size() > 1) {
 throw new Exception("multiple accounts by provider [${providerName}] for id [${providerUserId}]")
 }
 * **/ return map;
 }
 public Boolean createAccountForProvider(String providerName, String providerUserId, String displayName) {
 /**
 * log.debug("creating new account for displayName=${displayName} using provider=${providerName} with id ${providerUserId}")
 int result = jdbcTemplate.update(
 "insert into account (display_name, provider, provider_user_id) values (?, ?, ?)",
 displayName,
 providerName,
 providerUserId
 )
 if (result != 1) {
 log.warn("creation of account for provider [${providerName}] and id [${providerUserId}] failed")
 return false
 }
 * */ return true;
 }
}
 

index.html

<!doctype html>
<html xmlns:th="">
 <head>
 <title>Spring Pac4j Demo</title>
 </head>
 <body>
 <h2>Index Page sgdsfg</h2>
 </body>
</html>
 

login.html

<!doctype html>
<html xmlns:th=""
 xmlns:layout=""
 layout:decorator="layouts/default">
 <head>
 <title>Login</title>
 </head>
 <body>
 <div id="content" class="sign-in-page" layout:fragment="content">
 <h2>Sign In</h2>
 <a th:href="${casAuthUrl}" th:class="'oauth-login-link cas-login'">CAS</a>
 <a th:href="${gitHubAuthUrl}" th:class="'oauth-login-link github-login'">GitHub</a>
 <a th:href="${google2AuthUrl}" th:class="'oauth-login-link google-login'">Google</a>
 <a th:href="${twitterAuthUrl}" th:class="'oauth-login-link twitter-login'">Twitter</a>
 </div>
 </body>
</html>
 

文章来源:智云一二三科技

文章标题:pac4j – Java 权限引擎

文章地址:https://www.zhihuclub.com/185939.shtml

关于作者: 智云科技

热门文章

发表回复

您的电子邮箱地址不会被公开。

网站地图