需求:一個后台管理系統,現在用的springboot 微框架比較多, 所以這里也使用了, 后台權限用 spring security ,之前以前覺得聽復雜 。 后來發現還是蠻簡單的, 看了源代碼之后。模板用的 thymeleaf, 以上是背景介紹。
看看實現吧。
1.核心類(安全類)
package com.ycmedia.security; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private YcAnthencationProder provider; @Override protected void configure(HttpSecurity http) throws Exception { //允許訪問靜態資源 http.authorizeRequests() .antMatchers("/upload", "/css/**", "/js/**", "/images/**", "/resources/**", "/lib/**", "/skin/**", "/template/**") .permitAll(); //所有的訪問都需要權限驗證 http.authorizeRequests().anyRequest().authenticated(); //訪問失敗頁url http.formLogin().failureUrl("/login?error"). //登錄信息保存 successHandler(loginSuccessHandler()). //訪問成功頁url defaultSuccessUrl("/login") //默認訪問頁 .loginPage("/login") .permitAll().and().logout() .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) //注銷失敗跳轉到登錄頁面 .logoutSuccessUrl("/login").permitAll(); // 允許iframe 嵌套 http.headers().frameOptions().disable(); //關閉csrf 防止循環定向 http.csrf().disable(); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/resources/**"); web.ignoring().antMatchers("/webjars/**"); web.ignoring().antMatchers("/img/**"); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //采用自定義驗證 auth.authenticationProvider(provider); //需要采用加密 // auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(4); } /** * 用戶或者管理員登錄日志 */ @Bean public LoginSuccessHandler loginSuccessHandler(){ return new LoginSuccessHandler(); } }
======================這些配置其實很簡單, 很強大, 網上的例子很多。
2、啟動類 ,因為比較懶
package com.ycmedia; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; import org.springframework.boot.context.embedded.ErrorPage; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpStatus; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import com.ycmedia.service.UserService; @SpringBootApplication @EnableAutoConfiguration public class Application extends WebMvcConfigurerAdapter { @Bean public UserDetailsService userDetailsService() { return new UserService(); } /** * 自定義異常頁 */ @Bean public EmbeddedServletContainerCustomizer containerCustomizer() { return (container -> { ErrorPage error401Page = new ErrorPage(HttpStatus.FORBIDDEN, "/403.html"); ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html"); ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500.html"); container.addErrorPages(error401Page, error404Page, error500Page); }); } @Override public void addViewControllers(ViewControllerRegistry registry) { } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
這個啟動類, 加載了 核心實現 userDetailService。
3、實現類重寫。
package com.ycmedia.service; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.annotation.security.RolesAllowed; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import com.ycmedia.dao.UserDao; import com.ycmedia.entity.User; @Service public class UserService implements UserDetailsService { @Autowired private UserDao userDao; public List<User> loadAllUsers() { return userDao.loadAllUsers(); } /** * 保存用戶 * * @param user */ public void save(User user) { BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); if (user.getRole() == "0") { user.setRole("ROLE_ADMIN"); } else { user.setRole("ROLE_USER"); } user.setPassword(passwordEncoder.encode(user.getPassword())); userDao.insert(user); } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userDao.findUserByName(username); if (user == null) { throw new UsernameNotFoundException(username + " not found"); } System.err.println(user.getRole() + "正在執行查詢角色名稱"); return new UserDetails() { private static final long serialVersionUID = 3720901165271071386L; @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> auths = new ArrayList<>(); auths.add(new SimpleGrantedAuthority(user.getRole())); return auths; } @Override public String getPassword() { return user.getPassword(); } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }; } public User getUserByname(String username) { return userDao.findUserByName(username); } }
spring security 會自動調用被重寫的 loaduserbyusername ,獲取 用戶所有的信息 存在 Authentication
4.看下controller 的實現, 是基於注解的,因為項目比較簡單。
/**tpl-add * 跳轉到編輯廣告 * @return */ @PreAuthorize("hasAnyAuthority('ROLE_ADMIN')") @RequestMapping(value = "/product-edit") public ModelAndView toEditAd(@RequestParam("id")String id ,Creative creative){ creative = adservice.findAdById(id); return new ModelAndView("product-add" ,"creative",creative ); } /** * * 跳轉到編輯廣告 * @return */ @PreAuthorize("hasAnyAuthority('ROLE_ADMIN')") @RequestMapping(value = "/tpl-add") public ModelAndView toTplAdd(@ModelAttribute(value="tpl")CreativeTpl tpl){ return new ModelAndView("tpl-add" ); }
在方法 是作用注解, 普通用戶 沒有權限, 直接跳到403 頁面。
5、實體 User。 這個很簡單。
package com.ycmedia.entity; public class User { private Integer id; private String username; private String password; private String role; private String realname; private String mobile; private Integer state; private String info; 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 getRole() { return role; } public void setRole(String role) { this.role = role; } public String getRealname() { return realname; } public void setRealname(String realname) { this.realname = realname; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public Integer getState() { return state; } public void setState(Integer state) { this.state = state; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } }
7 。 表的話就用了一張。 user表
用戶對應的權限和用戶在一張表。
==========================================================================================================================================
看看源碼===========
==========================這里包括用戶名,密碼校驗等。
spring真的很強大
=======
附上 gitHup 完整項目地址:https://github.com/zhuliangxing823/quanming.git
