java中Spring Security的實例詳解
創(chuàng)新互聯(lián)客戶idc服務(wù)中心,提供成都服務(wù)器托管、成都服務(wù)器、成都主機托管、成都雙線服務(wù)器等業(yè)務(wù)的一站式服務(wù)。通過各地的服務(wù)中心,我們向成都用戶提供優(yōu)質(zhì)廉價的產(chǎn)品以及開放、透明、穩(wěn)定、高性價比的服務(wù),資深網(wǎng)絡(luò)工程師在機房提供7*24小時標準級技術(shù)保障。
spring security是一個多方面的安全認證框架,提供了基于JavaEE規(guī)范的完整的安全認證解決方案。并且可以很好與目前主流的認證框架(如CAS,中央授權(quán)系統(tǒng))集成。使用spring security的初衷是解決不同用戶登錄不同應(yīng)用程序的權(quán)限問題,說到權(quán)限包括兩部分:認證和授權(quán)。認證是告訴系統(tǒng)你是誰,授權(quán)是指知道你是誰后是否有權(quán)限訪問系統(tǒng)(授權(quán)后一般會在服務(wù)端創(chuàng)建一個token,之后用這個token進行后續(xù)行為的交互)。
spring security提供了多種認證模式,很多第三方的認證技術(shù)都可以很好集成:
這里只列舉了部分,后面會重點介紹如何集成CAS,搭建自己的認證服務(wù)。
在spring boot項目中使用spring security很容易,這里介紹如何基于內(nèi)存中的用戶和基于數(shù)據(jù)庫進行認證。
準備
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的兩個方法,分別定義什么請求需要什么權(quán)限,并且認證的用戶密碼分別是什么。
@Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { /** * 統(tǒng)一注冊純RequestMapping跳轉(zhuǎn)View的Controller */ @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("/login"); } }
添加登錄跳轉(zhuǎn)的URL,如果不加這個配置也會默認跳轉(zhuǎn)到/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>
基于內(nèi)存
SecurityConfig這個配置已經(jīng)是基于了內(nèi)存中的用戶進行認證的,
auth.inMemoryAuthentication()//基于內(nèi)存進行認證 .withUser("rhwayfun").password("1209")//用戶名密碼 .roles("USERS")//USER角色 .and() .withUser("admin").password("123456").roles("ADMIN");//ADMIN角色
訪問首頁會跳轉(zhuǎn)到登錄頁面這成功,使用配置的用戶登錄會跳轉(zhuǎn)到首頁。
基于數(shù)據(jù)庫
基于數(shù)據(jù)庫會復(fù)雜一些,不過原理是一致的只不過數(shù)據(jù)源從內(nèi)存轉(zhuǎn)到了數(shù)據(jù)庫。從基于內(nèi)存的例子我們大概知道spring security認證的過程:從內(nèi)存查找username為輸入值得用戶,如果存在著驗證其角色時候匹配,比如普通用戶不能訪問admin頁面,這點可以在controller層使用@PreAuthorize("hasRole('ROLE_ADMIN')")實現(xiàn),表示只有admin角色的用戶才能訪問該頁面,spring security中角色的定義都是以ROLE_開頭,后面跟上具體的角色名稱。
如果要基于數(shù)據(jù)庫,可以直接指定數(shù)據(jù)源即可:
auth.jdbcAuthentication().dataSource(securityDataSource);
只不過數(shù)據(jù)庫標是spring默認的,包括三張表:users(用戶信息表)、authorities(用戶角色信息表)
以下是查詢用戶信息以及創(chuàng)建用戶角色的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 = ?";
那么,如果要自定義數(shù)據(jù)庫表這需要配置如下,并且實現(xiàn)UserDetailsService接口:
auth.userDetailsService(userDetailsService()); @Bean public UserDetailsService userDetailsService() { return new CustomUserDetailsService(); }
CustomUserDetailsService實現(xiàn)如下:
@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); } }
我們需要實現(xiàn)loadUserByUsername方法,這里面其實級做了兩件事:查詢用戶信息并返回該用戶的角色信息。
數(shù)據(jù)庫設(shè)計如下:
數(shù)據(jù)庫設(shè)計
g_users:用戶基本信息表
g_authority:角色信息表
r_auth_user:用戶角色信息表,這里沒有使用外鍵約束。
使用mybatis generator生成mapper后,創(chuàng)建數(shù)據(jù)源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就很好實現(xiàn)了:
public interface UserRepository{ User findByUserName(String username); List<UserAuthority> findRoles(int userId); }
在數(shù)據(jù)庫插入相關(guān)數(shù)據(jù),重啟項目。仍然訪問首頁跳轉(zhuǎn)到登錄頁后輸入數(shù)據(jù)庫插入的用戶信息,如果成功跳轉(zhuǎn)到首頁這說明認證成功。
如有疑問請留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
分享題目:java中SpringSecurity的實例詳解
網(wǎng)頁路徑:http://jinyejixie.com/article6/pdsdig.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標簽優(yōu)化、企業(yè)網(wǎng)站制作、網(wǎng)站排名、App設(shè)計、用戶體驗、軟件開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)