详解Spring Boot 使用Spring security 集成CAS

1.创建工程

创建Maven工程:springboot-security-cas

2.加入依赖

创建工程后,打开pom.xml,在pom.xml中加入以下内容:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.3.RELEASE</version>
  </parent>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- security starter Poms -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <!-- security 对CAS支持 -->
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-cas</artifactId>
    </dependency>
    <!-- security taglibs -->
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-taglibs</artifactId>
    </dependency>
    <!-- 热加载 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

3.创建application.properties

创建application.properties文件,加入以下内容:

#CAS服务地址
cas.server.host.url=http://localhost:8081/cas
#CAS服务登录地址
cas.server.host.login_url=${cas.server.host.url}/login
#CAS服务登出地址
cas.server.host.logout_url=${cas.server.host.url}/logout?service=${app.server.host.url}
#应用访问地址
app.server.host.url=http://localhost:8080
#应用登录地址
app.login.url=/login
#应用登出地址
app.logout.url=/logout

4.创建入口启动类(MainConfig)

创建入口启动类MainConfig,完整代码如下:

package com.chengli.springboot; 

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; 

@RestController
@SpringBootApplication
public class MainConfig {
  public static void main(String[] args) {
    SpringApplication.run(MainConfig.class, args);
  } 

  @RequestMapping("/")
  public String index() {
    return "访问了首页哦";
  } 

  @RequestMapping("/hello")
  public String hello() {
    return "不验证哦";
  } 

  @PreAuthorize("hasAuthority('TEST')")//有TEST权限的才能访问
  @RequestMapping("/security")
  public String security() {
    return "hello world security";
  } 

  @PreAuthorize("hasAuthority('ADMIN')")//必须要有ADMIN权限的才能访问
  @RequestMapping("/authorize")
  public String authorize() {
    return "有权限访问";
  } 

  /**这里注意的是,TEST与ADMIN只是权限编码,可以自己定义一套规则,根据实际情况即可*/
}

5.创建Security配置类(SecurityConfig)

创建Security配置类SecurityConfig,完整代码如下:

package com.chengli.springboot.security; 

import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; 

import com.chengli.springboot.custom.CustomUserDetailsService;
import com.chengli.springboot.properties.CasProperties; 

@Configuration
@EnableWebSecurity //启用web权限
@EnableGlobalMethodSecurity(prePostEnabled = true) //启用方法验证
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Autowired
  private CasProperties casProperties; 

  /**定义认证用户信息获取来源,密码校验规则等*/
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    super.configure(auth);
    auth.authenticationProvider(casAuthenticationProvider());
    //inMemoryAuthentication 从内存中获取
    //auth.inMemoryAuthentication().withUser("chengli").password("123456").roles("USER")
    //.and().withUser("admin").password("123456").roles("ADMIN"); 

    //jdbcAuthentication从数据库中获取,但是默认是以security提供的表结构
    //usersByUsernameQuery 指定查询用户SQL
    //authoritiesByUsernameQuery 指定查询权限SQL
    //auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(query).authoritiesByUsernameQuery(query); 

    //注入userDetailsService,需要实现userDetailsService接口
    //auth.userDetailsService(userDetailsService);
  } 

  /**定义安全策略*/
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()//配置安全策略
      //.antMatchers("/","/hello").permitAll()//定义/请求不需要验证
      .anyRequest().authenticated()//其余的所有请求都需要验证
      .and()
    .logout()
      .permitAll()//定义logout不需要验证
      .and()
    .formLogin();//使用form表单登录 

    http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())
      .and()
      .addFilter(casAuthenticationFilter())
      .addFilterBefore(casLogoutFilter(), LogoutFilter.class)
      .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class); 

    //http.csrf().disable(); //禁用CSRF
  } 

  /**认证的入口*/
  @Bean
  public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
    CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
    casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());
    casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
    return casAuthenticationEntryPoint;
  } 

  /**指定service相关信息*/
  @Bean
  public ServiceProperties serviceProperties() {
    ServiceProperties serviceProperties = new ServiceProperties();
    serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
    serviceProperties.setAuthenticateAllArtifacts(true);
    return serviceProperties;
  } 

  /**CAS认证过滤器*/
  @Bean
  public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
    CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
    casAuthenticationFilter.setAuthenticationManager(authenticationManager());
    casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());
    return casAuthenticationFilter;
  } 

  /**cas 认证 Provider*/
  @Bean
  public CasAuthenticationProvider casAuthenticationProvider() {
    CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
    casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());
    //casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这里只是接口类型,实现的接口不一样,都可以的。
    casAuthenticationProvider.setServiceProperties(serviceProperties());
    casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
    casAuthenticationProvider.setKey("casAuthenticationProviderKey");
    return casAuthenticationProvider;
  } 

  /*@Bean
  public UserDetailsService customUserDetailsService(){
    return new CustomUserDetailsService();
  }*/ 

  /**用户自定义的AuthenticationUserDetailsService*/
  @Bean
  public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService(){
    return new CustomUserDetailsService();
  } 

  @Bean
  public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
    return new Cas20ServiceTicketValidator(casProperties.getCasServerUrl());
  } 

  /**单点登出过滤器*/
  @Bean
  public SingleSignOutFilter singleSignOutFilter() {
    SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
    singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl());
    singleSignOutFilter.setIgnoreInitConfiguration(true);
    return singleSignOutFilter;
  } 

  /**请求单点退出过滤器*/
  @Bean
  public LogoutFilter casLogoutFilter() {
    LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl(), new SecurityContextLogoutHandler());
    logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl());
    return logoutFilter;
  }
}

6.用户自定义类

(1)定义CasProperties,用于将properties文件指定的内容注入以方便使用,这里不注入也是可以的,可以获取Spring 当前的环境,代码如下:

package com.chengli.springboot.properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; 

/**
 * CAS的配置参数
 * @author ChengLi
 */
@Component
public class CasProperties {
  @Value("${cas.server.host.url}")
  private String casServerUrl; 

  @Value("${cas.server.host.login_url}")
  private String casServerLoginUrl; 

  @Value("${cas.server.host.logout_url}")
  private String casServerLogoutUrl; 

  @Value("${app.server.host.url}")
  private String appServerUrl; 

  @Value("${app.login.url}")
  private String appLoginUrl; 

  @Value("${app.logout.url}")
  private String appLogoutUrl;
......省略 getters setters 方法
}

(2)定义CustomUserDetailsService类,代码如下:

package com.chengli.springboot.custom; 

import java.util.HashSet;
import java.util.Set; 

import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException; 

/**
 * 用于加载用户信息 实现UserDetailsService接口,或者实现AuthenticationUserDetailsService接口
 * @author ChengLi
 *
 */
public class CustomUserDetailsService /*
  //实现UserDetailsService接口,实现loadUserByUsername方法
  implements UserDetailsService {
  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    System.out.println("当前的用户名是:"+username);
    //这里我为了方便,就直接返回一个用户信息,实际当中这里修改为查询数据库或者调用服务什么的来获取用户信息
    UserInfo userInfo = new UserInfo();
    userInfo.setUsername("admin");
    userInfo.setName("admin");
    Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>();
    AuthorityInfo authorityInfo = new AuthorityInfo("TEST");
    authorities.add(authorityInfo);
    userInfo.setAuthorities(authorities);
    return userInfo;
  }*/ 

  //实现AuthenticationUserDetailsService,实现loadUserDetails方法
  implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> { 

  @Override
  public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
    System.out.println("当前的用户名是:"+token.getName());
    /*这里我为了方便,就直接返回一个用户信息,实际当中这里修改为查询数据库或者调用服务什么的来获取用户信息*/
    UserInfo userInfo = new UserInfo();
    userInfo.setUsername("admin");
    userInfo.setName("admin");
    Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>();
    AuthorityInfo authorityInfo = new AuthorityInfo("TEST");
    authorities.add(authorityInfo);
    userInfo.setAuthorities(authorities);
    return userInfo;
  } 

}

(3)定义AuthorityInfo类,用于加载当前登录用户的权限信息,实现GrantedAuthority接口,代码如下:

package com.chengli.springboot.custom; 

import org.springframework.security.core.GrantedAuthority; 

/**
 * 权限信息
 *
 * @author ChengLi
 *
 */
public class AuthorityInfo implements GrantedAuthority {
  private static final long serialVersionUID = -175781100474818800L; 

  /**
   * 权限CODE
   */
  private String authority; 

  public AuthorityInfo(String authority) {
    this.authority = authority;
  } 

  @Override
  public String getAuthority() {
    return authority;
  } 

  public void setAuthority(String authority) {
    this.authority = authority;
  } 

}

(4)定义UserInfo类,用于加载当前用户信息,实现UserDetails接口,代码如下:

package com.chengli.springboot.custom; 

import java.util.Collection;
import java.util.HashSet;
import java.util.Set; 

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; 

/**
 * 用户信息
 * @、这里我写了几个较为常用的字段,id,name,username,password,可以根据实际的情况自己增加
 * @author ChengLi
 *
 */
public class UserInfo implements UserDetails {
  private static final long serialVersionUID = -1041327031937199938L; 

  /**
   * 用户ID
   */
  private Long id; 

  /**
   * 用户名称
   */
  private String name; 

  /**
   * 登录名称
   */
  private String username; 

  /**
   * 登录密码
   */
  private String password; 

  private boolean isAccountNonExpired = true; 

  private boolean isAccountNonLocked = true; 

  private boolean isCredentialsNonExpired = true; 

  private boolean isEnabled = true; 

  private Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>();
....省略getters setters 方法
}

到这里基本就已经完成了,运行CAS Server ,将以上的application.properties文件中的地址修改为实际的地址即可运行。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Boot中整合Spring Security并自定义验证代码实例

    最终效果 1.实现页面访问权限限制 2.用户角色区分,并按照角色区分页面权限 3.实现在数据库中存储用户信息以及角色信息 4.自定义验证代码 效果如下: 1.免验证页面 2.登陆页面 在用户未登录时,访问任意有权限要求的页面都会自动跳转到登陆页面. 3.需登陆才能查看的页面 用户登陆后,可以正常访问页面资源,同时可以正确显示用户登录名: 4.用户有角色区分,可以指定部分页面只允许有相应用户角色的人使用 4.1.只有ADMIN觉得用户才能查看的页面(权限不足) 4.2.只有ADMIN觉得用户才能查

  • Java中SpringSecurity密码错误5次锁定用户的实现方法

    Spring Security简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作. 下面看下实例代码: 第

  • JSP 开发之Spring Security详解

    JSP 开发之Spring Security详解 前言: spring Security是一个能够为基于Spring的企业应用系统提供描述性安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC(依赖注入,也称控制反转)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作. Spring Security 的前身是 Acegi Security ,是 Spring 项

  • Spring security实现权限管理示例

    Spring security实现权限管理示例,具体如下: 1.配置文件 1.POM.xml <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.o

  • JavaWeb开发之Spring+SpringMVC+MyBatis+SpringSecurity+EhCache+JCaptcha 完整Web基础框架

    简单介绍一下,本框架的基本功能点: Spring:整个框架的主体部分,这个自不用说. SpringMVC:MVC部分我还是比较喜欢Spring的. MyBatis:选型的时候选择这个ORM主要也是考虑其灵活性的问题,毕竟我也不知道,今后会遇到怎样的需求,用Hibernate一来是不太会用,二来,我还是比较喜欢直接写SQL来的简单一点. SpringSecurity:这个主要是安全框架,负责用户登录验证及整站权限分配的相关事项(权限分配真的很有用,这个我就不多说了). EhCache:一个非常流行

  • java中自定义Spring Security权限控制管理示例(实战篇)

    背景描述 项目中需要做细粒的权限控制,细微至url + httpmethod (满足restful,例如: https://.../xxx/users/1, 某些角色只能查看(HTTP GET), 而无权进行增改删(POST, PUT, DELETE)). 表设计 为避嫌,只列出要用到的关键字段,其余敬请自行脑补. 1.admin_user 管理员用户表, 关键字段( id, role_id ). 2.t_role 角色表, 关键字段( id, privilege_id ). 3.t_privi

  • 话说Spring Security权限管理(源码详解)

    最近项目需要用到Spring Security的权限控制,故花了点时间简单的去看了一下其权限控制相关的源码(版本为4.2). AccessDecisionManager spring security是通过AccessDecisionManager进行授权管理的,先来张官方图镇楼. AccessDecisionManager AccessDecisionManager 接口定义了如下方法: //调用AccessDecisionVoter进行投票(关键方法) void decide(Authent

  • 详解spring security 配置多个AuthenticationProvider

    前言 发现很少关于spring security的文章,基本都是入门级的,配个UserServiceDetails或者配个路由控制就完事了,而且很多还是xml配置,国内通病...so,本文里的配置都是java配置,不涉及xml配置,事实上我也不会xml配置 spring security的大体介绍 spring security本身如果只是说配置,还是很简单易懂的(我也不知道网上说spring security难,难在哪里),简单不需要特别的功能,一个WebSecurityConfigurerA

  • Spring Boot(四)之使用JWT和Spring Security保护REST API

    通常情况下,把API直接暴露出去是风险很大的,不说别的,直接被机器攻击就喝一壶的.那么一般来说,对API要划分出一定的权限级别,然后做一个用户的鉴权,依据鉴权结果给予用户开放对应的API.目前,比较主流的方案有几种: 用户名和密码鉴权,使用Session保存用户鉴权结果. 使用OAuth进行鉴权(其实OAuth也是一种基于Token的鉴权,只是没有规定Token的生成方式) 自行采用Token进行鉴权 第一种就不介绍了,由于依赖Session来维护状态,也不太适合移动时代,新的项目就不要采用了.

  • Spring Boot如何使用Spring Security进行安全控制

    我们在编写Web应用时,经常需要对页面做一些安全控制,比如:对于没有访问权限的用户需要转到登录表单页面.要实现访问控制的方法多种多样,可以通过Aop.拦截器实现,也可以通过框架实现(如:Apache Shiro.spring Security). 本文将具体介绍在Spring Boot中如何使用Spring Security进行安全控制. 准备工作 首先,构建一个简单的Web工程,以用于后续添加安全控制,也可以用之前Chapter3-1-2做为基础工程.若对如何使用Spring Boot构建We

  • Spring security实现登陆和权限角色控制

     随笔简介 1.spring版本:4.3.2.RELEASE+spring security 版本:4.1.2.RELEASE(其它不做说明) 2.所展示内容全部用注解配置 3.springmvc已经配置好,不作说明 4.会涉及到springmvc,spel,el的东西,不熟悉的同学可以先去看一下这方面内容,特别是springmvc 首先想一下,登陆需要什么,最简单的情况下,用户名,密码,然后比对数据库,如果吻合就跳转到个人页面,否则回到登陆页面,并且提示用户名密码错误.这个过程中应该还带有权限

随机推荐