什么是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是一个支持多种支持多种协议的身份认证的Java客户端。
2,pac4j的12种客户端认证机制:目前我只有用过第一和第八种。
- OAuth (1.0 & 2.0): Facebook, Twitter, Google, Yahoo, LinkedIn, Github… using the
pac4j-oauthmodule - CAS (1.0, 2.0, SAML, logout & proxy) + REST API support using the
pac4j-casmodule - HTTP (form, basic auth, IP, header, GET/POST parameter authentications) using the
pac4j-httpmodule - OpenID using the
pac4j-openidmodule - SAML (2.0) using the
pac4j-samlmodule - Google App Engine UserService using the
pac4j-gaemodule - OpenID Connect 1.0 using the
pac4j-oidcmodule - JWT using the
pac4j-jwtmodule - LDAP using the
pac4j-ldapmodule - relational DB using the
pac4j-sqlmodule - MongoDB using the
pac4j-mongomodule - Stormpath using the
pac4j-stormpathmodule.
3,maven配置
1 <dependency> 2 <groupId>org.pac4j</groupId> 3 <artifactId>spring-security-pac4j</artifactId> 4 <version>1.4.3</version> 5 </dependency> 6 <dependency> 7 <groupId>org.pac4j</groupId> 8 <artifactId>pac4j-oauth</artifactId> 9 <version>1.8.8</version> 10 </dependency> View Code
主要是三个jar包:
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
项目地址: https://github.com/pac4j/pac4j/tree/pac4j-3.1.0
———————-
pom.xml
<?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>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 = “https://casserverpac4j.herokuapp.com/login”;
@Value(“${oauth.callback.url}”)
private String oauthCallbackUrl;
@Autowired
AccountService accountService;
@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=”http://www.thymeleaf.org”>
<head>
<title>Spring Pac4j Demo</title>
</head>
<body>
<h2>Index Page sgdsfg</h2>
</body>
</html>123456789
login.html
<!doctype html>
<html xmlns:th=”http://www.thymeleaf.org”
xmlns:layout=”http://www.ultraq.net.nz/thymeleaf/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>
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Design for Hackers
David Kadavy / Wiley / 2011-10-18 / USD 39.99
Discover the techniques behind beautiful design?by deconstructing designs to understand them The term ?hacker? has been redefined to consist of anyone who has an insatiable curiosity as to how thin......一起来看看 《Design for Hackers》 这本书的介绍吧!