前端時間公司要作一個新的小產品,突發奇想用了spring-boot加spring-security作了登陸驗證,過程當中總感受晚上的資料很散,索性就整理了一下,固然我感受個人也不全哈哈哈,基本夠用。前端
先從最開始提及,引入maven依賴包寫入pom文件:java
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
因爲此次我使用的是spring-boot 1.3.6版本,因此全部範例都已此版本爲基礎。web
廢話不說,上源碼。spring
如今啓動類同包的地方創建spring security的配置類如:sql
package com.shineyue; 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.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import com.shineyue.security.CustomUserDetailsService; import com.shineyue.security.ShineyueAuthenticationProvider; /** * 集成spring-security * @author zml * */ @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ @Autowired private CustomUserDetailsService customUserDetailsService; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/","/login").permitAll()//1根路徑和/login路徑不攔截 .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") //2登錄頁面 .defaultSuccessUrl("/home") //3登錄成功轉向該頁面 .permitAll() .and() .logout().logoutUrl("/logout").logoutSuccessUrl("/login").invalidateHttpSession(true) .permitAll(); } //4 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(new ShineyueAuthenticationProvider(customUserDetailsService)); auth.eraseCredentials(true); } //5忽略靜態資源的攔截 @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/resources/static/**","/informationFeedback","/js/**","/error"); } @Bean public BCryptPasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(4); } }
其中的ShineyueAuthenticationProvider是咱們處理登陸信息基本邏輯的地方,代碼:數據庫
package com.shineyue.security; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.LockedException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; public class ShineyueAuthenticationProvider implements AuthenticationProvider { private UserDetailsService userDetailsService; public ShineyueAuthenticationProvider(UserDetailsService userDetailsService){ this.userDetailsService=userDetailsService; } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication; UserDetails userDetails =userDetailsService.loadUserByUsername(token.getName()); if(userDetails.getUsername()==null||userDetails.getUsername().equals("")){ throw new UsernameNotFoundException("用戶不存在"); }else if(!userDetails.isEnabled()){ throw new DisabledException("用戶已被禁用"); } String encryptedPassword = userDetails.getPassword(); // 數據庫用戶的密碼,通常都是加密過的 String inputPassword = (String) token.getCredentials(); // 用戶輸入的密碼 if(!encryptedPassword.equals(inputPassword)){ throw new BadCredentialsException("密碼無效,請從新輸入"); } return new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities()); } @Override public boolean supports(Class<?> authentication) { // TODO Auto-generated method stub return UsernamePasswordAuthenticationToken.class.equals(authentication); } }
customUserDetailsService對象是去數據庫查詢登陸信息的具體實現,如代碼:apache
package com.shineyue.security; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import javax.annotation.Resource; import org.apache.commons.logging.Log; import org.apache.commons.logging.impl.SLF4JLogFactory; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import com.shineyue.JkViewWebSocket; import com.shineyue.calldb.CallDbException; import com.shineyue.calldb.DbMethod; import com.shineyue.calldb.sql.NoSuchColumnException; import com.shineyue.calldb.sql.Row; import com.shineyue.calldb.sql.UnsupportedConversionException; import com.shineyue.jkjk.bean.UserInfo; @Component public class CustomUserDetailsService implements UserDetailsService { private static final Log log = SLF4JLogFactory.getLog(CustomUserDetailsService.class); /** * arg0 登陸時的用戶名 */ @Resource(name="dbTmpMethod") private DbMethod dbTmpMethod; @Override public UserDetails loadUserByUsername(String arg0) throws UsernameNotFoundException { System.out.println("arg0"+arg0); //在這裏執行查詢邏輯返回用戶信息 SUser su = new SUser(); if(dbTmpMethod==null){ log.error("login error -->dbTmpMethod is null"); }else{ UserInfo ui =new UserInfo(); ui.setName(arg0); //這下面的代碼是咱們自定義的數據庫查詢API,你們沒必要使用,使用咱們常見的mybatis便可 將查詢出的信息放入su對象中返回SecurityUser對象 try { List<Row> l =dbTmpMethod.Open("JKJK_COMMON_GET_USERINFO", ui); if(l.size()==1){ su.setDob(new Date()); su.setEmail("hahah@163.com"); su.setId(l.get(0).getDefInt("uid")); su.setName(l.get(0).getTrimString("name")); su.setPassword(l.get(0).getTrimString("password")); su.setMianAuth(l.get(0).getTrimString("auth")); su.setState(l.get(0).getDefInt("state")); String[] jgqx_arr=l.get(0).getTrimString("jgqx").split(","); if(jgqx_arr.length>0){ List<String> l_jgqx=Arrays.asList(jgqx_arr); su.setJgqx(l_jgqx); } } log.info("login user:"+l.get(0).getTrimString("name")); } catch (CallDbException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchColumnException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnsupportedConversionException e) { // TODO Auto-generated catch block e.printStackTrace(); } //System.out.println("dbTmpMethod is not null"); } return new SecurityUser(su); } }
這3個類基本上就是完成登陸的核心,固然咱們還須要一些對於用戶信息進行處理類。mybatis
好比:app
package com.shineyue.security; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; public class SUser implements Serializable { /** * */ private static final long serialVersionUID = -7019867470266738718L; private int id; private String name; private String email; private String password; private Date dob; private String mianAuth; private int state; private Set<SRole> sRoles = new HashSet<SRole>(0); private List<String> jgqx=new ArrayList<String>(); public SUser(){ } public List<String> getJgqx() { return jgqx; } public void setJgqx(List<String> jgqx) { this.jgqx = jgqx; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getDob() { return dob; } public void setDob(Date dob) { this.dob = dob; } public Set<SRole> getsRoles() { return sRoles; } public void setsRoles(Set<SRole> sRoles) { this.sRoles = sRoles; } public static long getSerialversionuid() { return serialVersionUID; } public String getMianAuth() { return mianAuth; } public void setMianAuth(String mianAuth) { this.mianAuth = mianAuth; } public int getState() { return state; } public void setState(int state) { this.state = state; } }
package com.shineyue.security; public class SRole { private int id; private String name; private int uid; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getUid() { return uid; } public void setUid(int uid) { this.uid = uid; } }
package com.shineyue.security; import java.util.ArrayList; import java.util.Collection; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; public class SecurityUser implements UserDetails { private SUser user; /** * */ private static final long serialVersionUID = -1623385418837308233L; public SecurityUser(SUser u){ this.user=u; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); //放入用戶的權限和角色信息 SimpleGrantedAuthority authority= new SimpleGrantedAuthority("auth:"+this.user.getMianAuth()); authorities.add(authority); authorities.add(authority1); return authorities; } @Override public String getPassword() { // TODO Auto-generated method stub return this.user.getPassword(); } @Override public String getUsername() { // TODO Auto-generated method stub return this.user.getName(); } @Override public boolean isAccountNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isAccountNonLocked() { // TODO Auto-generated method stub return true; } @Override public boolean isCredentialsNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isEnabled() { if(this.user.getState()==2){ return false; }else{ return true; } } }
而後就是在一個Controller類中寫入login方法用於登陸時信息的返回和狀態更改具體代碼以下:maven
@RequestMapping("login") public String login(@RequestParam(value="error", required=false) String error, @RequestParam(value="logout", required=false) String logout,HttpServletRequest request, HttpServletResponse response,ModelMap model){ if (error != null) { AuthenticationException ex = (AuthenticationException)request.getSession() .getAttribute("SPRING_SECURITY_LAST_EXCEPTION"); model.put("error", ex.getMessage()); } else if (logout != null) { model.put("logout", "Logout successful"); } return "login"; }
以後就是寫一個登陸頁,別忘了等於的用戶名和密碼控件名詞必須用username和password