这里有新鲜出炉的 Java 并发编程示例,程序狗速度看过来!
Java 程序设计语言
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称.
这篇文章主要介绍了 java 中 Spring Security 的实例详解的相关资料, spring security 是一个多方面的安全认证框架,提供了基于 JavaEE 规范的完整的安全认证解决方案,需要的朋友可以参考下
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>
这里需要覆盖 WebSecurityConfigurerAdapter 的两个方法,分别定义什么请求需要什么权限,并且认证的用户密码分别是什么.
@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();
}
}
* 统一注册纯RequestMapping跳转View的Controller
@Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter {
/***/
添加登录跳转的 URL,如果不加这个配置也会默认跳转到 / login 下,所以这里还可以自定义登录的请求路径.
* /
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login ").setViewName(" / 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 类查看):
那么,如果要自定义数据库表这需要配置如下,并且实现 UserDetailsService 接口:
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 = ?";
CustomUserDetailsService 实现如下:
auth.userDetailsService(userDetailsService());
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
我们需要实现 loadUserByUsername 方法,这里面其实级做了两件事:查询用户信息并返回该用户的角色信息.
@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);
}
}
数据库设计如下:
数据库设计
g_users: 用户基本信息表
g_authority: 角色信息表
r_auth_user: 用户角色信息表,这里没有使用外键约束.
使用 mybatis generator 生成 mapper 后,创建数据源 SecurityDataSource.
那么 DAO UserRepository 就很好实现了:
@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;
}
}
在数据库插入相关数据,重启项目.仍然访问首页跳转到登录页后输入数据库插入的用户信息,如果成功跳转到首页这说明认证成功.
public interface UserRepository {
User findByUserName(String username);
List < UserAuthority > findRoles(int userId);
}
来源: http://www.phperz.com/article/18/0113/354130.html