SpringSecurity中怎么保護(hù)程序安全,針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。
梅列網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),梅列網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為梅列上千余家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)公司要多少錢,請找那個(gè)售后服務(wù)好的梅列做網(wǎng)站的公司定做!
首先,引入依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency>
引入此依賴之后,你的web程序?qū)碛幸韵鹿δ埽?/p>
所有請求路徑都需要認(rèn)證 不需要特定的角色和權(quán)限 沒有登錄頁面,使用HTTP基本身份認(rèn)證 只有一個(gè)用戶,名稱為user
配置SpringSecurity
springsecurity配置項(xiàng),最好保存在一個(gè)單獨(dú)的配置類中:
@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { }
配置用戶認(rèn)證方式
首先,要解決的就是用戶注冊,保存用戶的信息。springsecurity提供四種存儲用戶的方式:
基于內(nèi)存(生產(chǎn)肯定不使用) 基于JDBC 基于LDAP 用戶自定義(最常用)
使用其中任意一種方式,需要覆蓋configure(AuthenticationManagerBuilder auth)方法:
@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { }}
1.基于內(nèi)存
@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("zhangsan").password("123").authorities("ROLE_USER") .and() .withUser("lisi").password("456").authorities("ROLE_USER");}
2.基于JDBC
@AutowiredDataSource dataSource;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication() .dataSource(dataSource);}
基于JDBC的方式,你必須有一些特定表表,而且字段滿足其查詢規(guī)則:
public static final String DEF_USERS_BY_USERNAME_QUERY = "select username,password,enabled " + "from users " + "where username = ?";public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY = "select username,authority " + "from authorities " + "where username = ?";public static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY = "select g.id, g.group_name, ga.authority " + "from groups g, group_members gm, group_authorities ga " + "where gm.username = ? " + "and g.id = ga.group_id " + "and g.id = gm.group_id";
當(dāng)然,你可以對這些語句進(jìn)行一下修改:
@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication().dataSource(dataSource) .usersByUsernameQuery("select username, password, enabled from Users " + "where username=?") .authoritiesByUsernameQuery("select username, authority from UserAuthorities " + "where username=?");
這有一個(gè)問題,你數(shù)據(jù)庫中的密碼可能是一種加密方式加密過的,而用戶傳遞的是明文,比較的時(shí)候需要進(jìn)行加密處理,springsecurity也提供了相應(yīng)的功能:
@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication().dataSource(dataSource) .usersByUsernameQuery("select username, password, enabled from Users " + "where username=?") .authoritiesByUsernameQuery("select username, authority from UserAuthorities " + "where username=?") .passwordEncoder(new StandardPasswordEncoder("53cr3t");
passwordEncoder方法傳遞的是PasswordEncoder接口的實(shí)現(xiàn),其默認(rèn)提供了一些實(shí)現(xiàn),如果都不滿足,你可以實(shí)現(xiàn)這個(gè)接口:
BCryptPasswordEncoder NoOpPasswordEncoder Pbkdf2PasswordEncoder SCryptPasswordEncoder StandardPasswordEncoder(SHA-256)
3.基于LDAP
@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.ldapAuthentication() .userSearchBase("ou=people") .userSearchFilter("(uid={0})") .groupSearchBase("ou=groups") .groupSearchFilter("member={0}") .passwordCompare() .passwordEncoder(new BCryptPasswordEncoder()) .passwordAttribute("passcode") .contextSource() .root("dc=tacocloud,dc=com") .ldif("classpath:users.ldif");
4.用戶自定義方式(最常用)
首先,你需要一個(gè)用戶實(shí)體類,它實(shí)現(xiàn)UserDetails接口,實(shí)現(xiàn)這個(gè)接口的目的是為框架提供更多的信息,你可以把它看作框架使用的實(shí)體類:
@Datapublic class User implements UserDetails { private Long id; private String username; private String password; private String fullname; private String city; private String phoneNumber; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } @Override public boolean isAccountNonExpired() { return false; } @Override public boolean isAccountNonLocked() { return false; } @Override public boolean isCredentialsNonExpired() { return false; } @Override public boolean isEnabled() { return false; }}
有了實(shí)體類,你還需要Service邏輯層,springsecurity提供了UserDetailsService接口,見名知意,你只要通過loadUserByUsername返回一個(gè)UserDetails對象就成,無論是基于文件、基于數(shù)據(jù)庫、還是基于LDAP,剩下的對比判斷交個(gè)框架完成:
@Servicepublic class UserService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { return null; } }
最后,進(jìn)行應(yīng)用:
@Autowiredprivate UserDetailsService userDetailsService;@Beanpublic PasswordEncoder encoder() { return new StandardPasswordEncoder("53cr3t");}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(encoder());}
配置認(rèn)證路徑
知道了如何認(rèn)證,但現(xiàn)在有幾個(gè)問題,比如,用戶登錄頁面就不需要認(rèn)證,可以用configure(HttpSecurity http)對認(rèn)證路徑進(jìn)行配置:
@Overrideprotected void configure(HttpSecurity http) throws Exception { }
你可以通過這個(gè)方法,實(shí)現(xiàn)以下功能:
在提供接口服務(wù)前,判斷請求必須滿足某些條件 配置登錄頁面 允許用戶注銷登錄 跨站點(diǎn)偽造請求防護(hù)
1.保護(hù)請求
@Overrideprotected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/design", "/orders").hasRole("ROLE_USER") .antMatchers(“/”, "/**").permitAll();}
要注意其順序,除了hasRole和permitAll還有其它訪問認(rèn)證方法:
access(String) 如果給定的SpEL表達(dá)式的計(jì)算結(jié)果為true,則允許訪問 anonymous() 允許訪問匿名用戶 authenticated() 允許訪問經(jīng)過身份驗(yàn)證的用戶 denyAll() 無條件拒絕訪問 fullyAuthenticated() 如果用戶完全通過身份驗(yàn)證,則允許訪問 hasAnyAuthority(String...) 如果用戶具有任何給定權(quán)限,則允許訪問 hasAnyRole(String...) 如果用戶具有任何給定角色,則允許訪問 hasAuthority(String) 如果用戶具有給定權(quán)限,則允許訪問 hasIpAddress(String) 如果請求來自給定的IP地址,則允許訪問 hasRole(String) 如果用戶具有給定角色,則允許訪問 not() 否定任何其他訪問方法的影響 permitAll() 允許無條件訪問 rememberMe() 允許通過remember-me進(jìn)行身份驗(yàn)證的用戶訪問
大部分方法是為特定方式準(zhǔn)備的,但是access(String)可以使用SpEL進(jìn)一些特殊的設(shè)置,但其中很大一部分也和上面的方法相同:
authentication 用戶的身份驗(yàn)證對象 denyAll 始終評估為false hasAnyRole(list of roles) 如果用戶具有任何給定角色,則為true hasRole(role) 如果用戶具有給定角色,則為true hasIpAddress(IP address) 如果請求來自給定的IP地址,則為true isAnonymous() 如果用戶是匿名用戶,則為true isAuthenticated() 如果用戶已通過身份驗(yàn)證,則為true isFullyAuthenticated() 如果用戶已完全通過身份驗(yàn)證,則為true(未通過remember-me進(jìn)行身份驗(yàn)證) isRememberMe() 如果用戶通過remember-me進(jìn)行身份驗(yàn)證,則為true permitAll 始終評估為true principal 用戶的主要對象
示例:
@Overrideprotected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/design", "/orders").access("hasRole('ROLE_USER')") .antMatchers(“/”, "/**").access("permitAll");}
方法 | 作用 |
---|---|
表達(dá)式 | 作用 |
@Overrideprotected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/design", "/orders").access("hasRole('ROLE_USER') && " + "T(java.util.Calendar).getInstance().get("+"T(java.util.Calendar).DAY_OF_WEEK) == " + "T(java.util.Calendar).TUESDAY") .antMatchers(“/”, "/**").access("permitAll");}
2.配置登錄頁面
@Overrideprotected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/design", "/orders").access("hasRole('ROLE_USER')") .antMatchers(“/”, "/**").access("permitAll") .and() .formLogin() .loginPage("/login");}// 增加視圖處理器@Overridepublic void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("home"); registry.addViewController("/login");}
默認(rèn)情況下,希望傳遞的是username和password,當(dāng)然你可以修改:
.and() .formLogin() .loginPage("/login") .loginProcessingUrl("/authenticate") .usernameParameter("user") .passwordParameter("pwd")
也可修改默認(rèn)登錄成功的頁面:
.and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/design")
3.配置登出
.and() .logout() .logoutSuccessUrl("/")
4.csrf攻擊
springsecurity默認(rèn)開啟了防止csrf攻擊,你只需要在傳遞的時(shí)候加上:
<input type="hidden" name="_csrf" th:value="${_csrf.token}"/>
當(dāng)然,你也可以關(guān)閉,但是不建議這樣做:
.and() .csrf() .disable()
知道用戶是誰
僅僅控制用戶登錄有時(shí)候是不夠的,你可能還想在程序的其它地方獲取已經(jīng)登錄的用戶信息,有幾種方式可以做到:
將Principal對象注入控制器方法 將Authentication對象注入控制器方法 使用SecurityContextHolder獲取安全上下文 使用@AuthenticationPrincipal注解方法
1.將Principal對象注入控制器方法
@PostMappingpublic String processOrder(@Valid Order order, Errors errors,SessionStatus sessionStatus,Principal principal) { ... User user = userRepository.findByUsername(principal.getName()); order.setUser(user); ...}
2.將Authentication對象注入控制器方法
@PostMappingpublic String processOrder(@Valid Order order, Errors errors, SessionStatus sessionStatus, Authentication authentication) { ... User user = (User) authentication.getPrincipal(); order.setUser(user); ...}
3.使用SecurityContextHolder獲取安全上下文
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); User user = (User) authentication.getPrincipal();
4.使用@AuthenticationPrincipal注解方法
@PostMappingpublic String processOrder(@Valid Order order, Errors errors,SessionStatus sessionStatus, @AuthenticationPrincipal User user) { if (errors.hasErrors()) { return "orderForm"; } order.setUser(user); orderRepo.save(order); sessionStatus.setComplete(); return "redirect:/";}
關(guān)于SpringSecurity中怎么保護(hù)程序安全問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。
文章標(biāo)題:SpringSecurity中怎么保護(hù)程序安全
網(wǎng)站URL:http://muchs.cn/article18/pieddp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、品牌網(wǎng)站制作、定制網(wǎng)站、品牌網(wǎng)站設(shè)計(jì)、軟件開發(fā)、Google
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)