java中Spring Security的实例详解

发布时间 - 2026-01-11 03:06:37    点击率:

java中Spring Security的实例详解

spring security是一个多方面的安全认证框架,提供了基于JavaEE规范的完整的安全认证解决方案。并且可以很好与目前主流的认证框架(如CAS,中央授权系统)集成。使用spring security的初衷是解决不同用户登录不同应用程序的权限问题,说到权限包括两部分:认证和授权。认证是告诉系统你是谁,授权是指知道你是谁后是否有权限访问系统(授权后一般会在服务端创建一个token,之后用这个token进行后续行为的交互)。

spring security提供了多种认证模式,很多第三方的认证技术都可以很好集成:

  • Form-based authentication (用于简单的用户界面)
  • OpenID 认证
  • Authentication based on pre-established request headers (such as Computer - Associates Siteminder)根据预先建立的请求头进行验证
  • JA-SIG Central Authentication Service ( CAS, 一个开源的SSO系统)
  • Java Authentication and Authorization Service (JAAS)

这里只列举了部分,后面会重点介绍如何集成CAS,搭建自己的认证服务。

在spring boot项目中使用spring security很容易,这里介绍如何基于内存中的用户和基于数据库进行认证。

准备

pom依赖:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
        <version>1.5.1.RELEASE</version>
      </dependency>

配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Bean
  public UserDetailsService userDetailsService() {
    return new CustomUserDetailsService();
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().withUser("rhwayfun").password("1209").roles("USERS")
        .and().withUser("admin").password("123456").roles("ADMIN");
    //auth.jdbcAuthentication().dataSource(securityDataSource);
    //auth.userDetailsService(userDetailsService());
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()//配置安全策略
        //.antMatchers("/","/index").permitAll()//定义/请求不需要验证
        .anyRequest().authenticated()//其余的所有请求都需要验证
        .and()
        .formLogin()
        .loginPage("/login")
        .defaultSuccessUrl("/index")
        .permitAll()
        .and()
        .logout()
        .logoutSuccessUrl("/login")
        .permitAll();//定义logout不需要验证

    http.csrf().disable();
  }

}

这里需要覆盖WebSecurityConfigurerAdapter的两个方法,分别定义什么请求需要什么权限,并且认证的用户密码分别是什么。

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
  /**
   * 统一注册纯RequestMapping跳转View的Controller
   */
  @Override
  public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/login").setViewName("/login");
  }
}

添加登录跳转的URL,如果不加这个配置也会默认跳转到/login下,所以这里还可以自定义登录的请求路径。

登录页面:

<!DOCTYPE html>

<%--<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>--%>

<html>
<head>
  <meta charset="utf-8">
  <title>Welcome SpringBoot</title>
  <script src="/js/jquery-3.1.1.min.js"></script>
  <script src="/js/index.js"></script>
</head>
<body>

<form name="f" action="/login" method="post">
  <input id="name" name="username" type="text"/><br>
  <input id="password" name="password" type="password"><br>
  <input type="submit" value="login">
  <input name="_csrf" type="hidden" value="${_csrf}"/>
</form>

<p id="users">

</p>

<script>
  $(function () {
    $('[name=f]').focus()
  })
</script>
</body>

</html>

基于内存

SecurityConfig这个配置已经是基于了内存中的用户进行认证的,

auth.inMemoryAuthentication()//基于内存进行认证
.withUser("rhwayfun").password("1209")//用户名密码
.roles("USERS")//USER角色
        .and()
        .withUser("admin").password("123456").roles("ADMIN");//ADMIN角色

访问首页会跳转到登录页面这成功,使用配置的用户登录会跳转到首页。

基于数据库

基于数据库会复杂一些,不过原理是一致的只不过数据源从内存转到了数据库。从基于内存的例子我们大概知道spring security认证的过程:从内存查找username为输入值得用户,如果存在着验证其角色时候匹配,比如普通用户不能访问admin页面,这点可以在controller层使用@PreAuthorize("hasRole('ROLE_ADMIN')")实现,表示只有admin角色的用户才能访问该页面,spring security中角色的定义都是以ROLE_开头,后面跟上具体的角色名称。

如果要基于数据库,可以直接指定数据源即可:

auth.jdbcAuthentication().dataSource(securityDataSource);

只不过数据库标是spring默认的,包括三张表:users(用户信息表)、authorities(用户角色信息表)

以下是查询用户信息以及创建用户角色的SQL(部分,详细可到JdbcUserDetailsManager类查看):

public static final String DEF_CREATE_USER_SQL = "insert into users (username, password, enabled) values (?,?,?)";

public static final String DEF_INSERT_AUTHORITY_SQL = "insert into authorities (username, authority) values (?,?)";

public static final String DEF_USER_EXISTS_SQL = "select username from users where username = ?";

那么,如果要自定义数据库表这需要配置如下,并且实现UserDetailsService接口:

auth.userDetailsService(userDetailsService());

@Bean
  public UserDetailsService userDetailsService() {
    return new CustomUserDetailsService();
  }

CustomUserDetailsService实现如下:

@Service
public class CustomUserDetailsService implements UserDetailsService {

  /** Logger */
  private static Logger log = LoggerFactory.getLogger(CustomUserDetailsService.class);

  @Resource
  private UserRepository userRepository;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    if (StringUtils.isBlank(username)) {
      throw new IllegalArgumentException("username can't be null!");
    }
    User user;
    try {
      user = userRepository.findByUserName(username);
    } catch (Exception e) {
      log.error("读取用户信息异常,", e);
      return null;
    }
    if (user == null) {
      return null;
    }
    List<UserAuthority> roles = userRepository.findRoles(user.getUserId());
    List<SimpleGrantedAuthority> authorities = new ArrayList<>();
    for (UserAuthority role : roles) {
      SimpleGrantedAuthority authority = new SimpleGrantedAuthority(String.valueOf(role.getAuthId()));
      authorities.add(authority);
    }
    return new org.springframework.security.core.userdetails.User(username, "1234", authorities);
  }


}

我们需要实现loadUserByUsername方法,这里面其实级做了两件事:查询用户信息并返回该用户的角色信息。

数据库设计如下:

数据库设计

g_users:用户基本信息表
g_authority:角色信息表
r_auth_user:用户角色信息表,这里没有使用外键约束。

使用mybatis generator生成mapper后,创建数据源SecurityDataSource。

@Configuration
@ConfigurationProperties(prefix = "security.datasource")
@MapperScan(basePackages = DataSourceConstants.MAPPER_SECURITY_PACKAGE, sqlSessionFactoryRef = "securitySqlSessionFactory")
public class SecurityDataSourceConfig {

  private String url;

  private String username;

  private String password;

  private String driverClassName;

  @Bean(name = "securityDataSource")
  public DataSource securityDataSource() {
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName(driverClassName);
    dataSource.setUrl(url);
    dataSource.setUsername(username);
    dataSource.setPassword(password);
    return dataSource;
  }

  @Bean(name = "securityTransactionManager")
  public DataSourceTransactionManager securityTransactionManager() {
    return new DataSourceTransactionManager(securityDataSource());
  }

  @Bean(name = "securitySqlSessionFactory")
  public SqlSessionFactory securitySqlSessionFactory(@Qualifier("securityDataSource") DataSource securityDataSource)
      throws Exception {
    final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
    sessionFactory.setDataSource(securityDataSource);
    sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
        .getResources(DataSourceConstants.MAPPER_SECURITY_LOCATION));
    return sessionFactory.getObject();
  }

  public String getUrl() {
    return url;
  }

  public void setUrl(String url) {
    this.url = url;
  }

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public String getDriverClassName() {
    return driverClassName;
  }

  public void setDriverClassName(String driverClassName) {
    this.driverClassName = driverClassName;
  }
}

那么DAO UserRepository就很好实现了:

public interface UserRepository{

  User findByUserName(String username);

  List<UserAuthority> findRoles(int userId);

}

在数据库插入相关数据,重启项目。仍然访问首页跳转到登录页后输入数据库插入的用户信息,如果成功跳转到首页这说明认证成功。

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


# java  # Spring  # Security  # Security的使用方法  # Security详解  # java的java.security.egd源码解读  # Spring Security拦截器引起Java CORS跨域失败的问题及解决  # Java中SpringSecurity密码错误5次锁定用户的实现方法  # java中自定义Spring Security权限控制管理示例(实战篇)  # java.security.egd 作用详解  # 跳转到  # 很好  # 首页  # 不需要  # 自定义  # 跳转  # 用户登录  # 自己的  # 安全认证  # 是一个  # 只不过  # 也会  # 还可以  # 如有  # 是指  # 会在  # 说到  # 很容易  # 转到  # 希望能 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Android中AutoCompleteTextView自动提示  Laravel的.env文件有什么用_Laravel环境变量配置与管理详解  Laravel如何配置和使用缓存?(Redis代码示例)  如何在Windows服务器上快速搭建网站?  Laravel如何从数据库删除数据_Laravel destroy和delete方法区别  Laravel如何实现多对多模型关联?(Eloquent教程)  javascript中数组(Array)对象和字符串(String)对象的常用方法总结  如何在IIS中配置站点IP、端口及主机头?  如何在云主机快速搭建网站站点?  音响网站制作视频教程,隆霸音响官方网站?  Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置  JavaScript如何实现错误处理_try...catch如何捕获异常?  Laravel中间件如何使用_Laravel自定义中间件实现权限控制  Python企业级消息系统教程_KafkaRabbitMQ高并发应用  高端网站建设与定制开发一站式解决方案 中企动力  Laravel中的Facade(门面)到底是什么原理  Laravel怎么实现模型属性的自动加密  韩国服务器如何优化跨境访问实现高效连接?  网站建设保证美观性,需要考虑的几点问题!  如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环  猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?  网易LOFTER官网链接 老福特网页版登录地址  佛山企业网站制作公司有哪些,沟通100网上服务官网?  如何在云服务器上快速搭建个人网站?  济南网站建设制作公司,室内设计网站一般都有哪些功能?  JS实现鼠标移上去显示图片或微信二维码  Laravel怎么多语言本地化设置_Laravel语言包翻译与Locale动态切换【手册】  高端建站如何打造兼具美学与转化的品牌官网?  如何用AI一键生成爆款短视频文案?小红书AI文案写作指令【教程】  Laravel DB事务怎么使用_Laravel数据库事务回滚操作  Windows驱动无法加载错误解决方法_驱动签名验证失败处理步骤  如何在万网利用已有域名快速建站?  Linux虚拟化技术教程_KVMQEMU虚拟机安装与调优  如何快速使用云服务器搭建个人网站?  Laravel怎么集成Log日志记录_Laravel单文件与每日日志配置及自定义通道【详解】  实现点击下箭头变上箭头来回切换的两种方法【推荐】  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南  手机怎么制作网站教程步骤,手机怎么做自己的网页链接?  浅谈redis在项目中的应用  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  如何快速完成中国万网建站详细流程?  Laravel与Inertia.js怎么结合_使用Laravel和Inertia构建现代单页应用  Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives  Laravel如何自定义错误页面(404, 500)?(代码示例)  Laravel如何实现用户角色和权限系统_Laravel角色权限管理机制  Laravel如何使用Livewire构建动态组件?(入门代码)  焦点电影公司作品,电影焦点结局是什么?  ai格式如何转html_将AI设计稿转换为HTML页面流程【页面】  高防服务器租用指南:配置选择与快速部署攻略