java中Spring Security的实例详解

网友投稿 384 2023-04-09


java中Spring Security的实例详解

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依赖:

org.springframework.boot

spring-boot-starter-security

1.5.1.RELEASE

配置:

@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(userUUaENZpzXDetailsService());

}

@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下,所以这里还可以自定义登录的请求路径。

登录页面:

<%--<%@ taglib prefix="spring" uri="http://springframework.org/tags"%>

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



基于内存

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 roles = userRepository.findRoles(user.getUserId());

List 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 urUUaENZpzXl;

}

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 findRoles(int userId);

}

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

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java 在file的尾部添加数据的两种方法总结
下一篇:mybatis实现表与对象的关联关系_动力节点Java学院整理
相关文章

 发表评论

暂时没有评论,来抢沙发吧~