ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

PAC4J 初探

2021-09-02 16:02:58  阅读:125  来源: 互联网

标签:PAC4J return 初探 springframework import org security public


什么是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="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>
  • 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>
  • run

  • index

 

本文转载自:https://blog.csdn.net/change_on/article/details/76302161

标签:PAC4J,return,初探,springframework,import,org,security,public
来源: https://www.cnblogs.com/wpcnblog/p/15219139.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有