OAuth认证机制入门篇

什么是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种客户端认证机制:目前我只有用过第一和第八种。

  1. OAuth  (1.0 & 2.0): Facebook, Twitter, Google, Yahoo, LinkedIn, Github… using the  pac4j-oauth  module
  2. CAS  (1.0, 2.0, SAML, logout & proxy) + REST API support using the  pac4j-cas  module
  3. HTTP  (form, basic auth, IP, header, GET/POST parameter authentications) using the  pac4j-http  module
  4. OpenID  using the  pac4j-openid  module
  5. SAML  (2.0) using the  pac4j-saml  module
  6. Google App Engine  UserService using the  pac4j-gae  module
  7. OpenID Connect  1.0 using the  pac4j-oidc  module
  8. JWT  using the  pac4j-jwt  module
  9. LDAP  using the  pac4j-ldap  module
  10. relational DB  using the  pac4j-sql  module
  11. MongoDB  using the  pac4j-mongo  module
  12. Stormpath  using the  pac4j-stormpath  module.

OAuth认证机制入门篇

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包:

OAuth认证机制入门篇

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>

原文 

http://www.iigrowing.cn/oauth_ren_zheng_ji_zhi_ru_men_pian.html

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » OAuth认证机制入门篇

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址