天天看點

Spring Security - 使用者密碼配置

Spring Security 使用者密碼配置

配置檔案

Spring Boot中整合Spring Security隻需添加一個依賴即可,非常友善,啟動項目時:控制台會輸出一個密碼,在浏覽器通路時會彈出一個登入框,預設使用者為user,而密碼就是控制台輸出的那段字元串。

那這樣就會有一個問題,每次通路都需要複制控制台的密碼,當然,這個是可以配置的,可以在配置檔案當中進行如下配置。

spring.security.user.name=user
spring.security.user.password=youyuan 
           

此時,通路浏覽器登入即可。

記憶體配置

當然也可以基于記憶體進行配置,建立一個類繼承自WebSecurityConfigurerAdapter然後實作其configuration方法即可。

@Configuration 
public class MultiHttpSecurityConfig extend WebSecurityConfigurerAdapter{

    //對密碼不進行加密處理
    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    @Autowired
    /*使用者認證*/
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("youyuan").password("1011").roles("admin")
                .and()
                .withUser("zs").password("1011").roles("user");
    }
}

           

注意:基于記憶體的使用者配置在配置角色時不需要添加"ROLE_ "字首

資料庫配置

當然在實際開發情況下,使用者與密碼還是要從資料庫當中加載,基于資料庫進行認證。

首先我們準備三個表,分别為使用者,角色,還有使用者角色表。使用者角色表關聯每個使用者所對應的角色。

Spring Security - 使用者密碼配置

在配置基本的資料庫資訊:

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.password=root
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://localhost:3306/testcharacterEncoding=utf-8&serverTimezone=UTC
           

然後在建立對應的實體類:

@Data
public class User implements UserDetails {
    private Integer id;
    private String username;
    private String password;
    private Boolean enabled;
    private Boolean locked;
    private List<Role> roles;
    @Override
    /*傳回使用者所有角色*/
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (Role role : this.roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName()));
        }
        return authorities;
    }

    @Override
    /*賬戶是否沒有過期*/
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    /*賬戶是否未鎖定*/
    public boolean isAccountNonLocked() {
        return !locked;
    }

    @Override
    /*密碼是否未過期*/
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public String getPassword() {
        return password;
    }


}

           

在UserService類中實作UserDetailsService接口

@Service
public class UserService implements UserDetailsService {

    @Autowired
    UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.loadUserByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("使用者不存在!");
        }
        /**
        *查詢出相應的角色
        *添加角色到user中**/
        user.setRoles(userMapper.getUserRolesById(user.getId()));
        return user;
    }
}

           

最後在Spring Security進行配置:

@Configuration
public class SecurityConfig  extends WebSecurityConfigurerAdapter {

    @Autowired
    UserService userService;

    @Override
    /**
    *使用者認證
    **/
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }

    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    /**
    **表單配置詳解
    **/
	@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()//開啟登入配置 
        .anyRequest().authenticated() //表示通路接口,需要進行認證
        .and()
        .formLogin()
        .loginProcessingUrl("/doLogin")
                .loginPage("/login") //預設的登入頁面
                .usernameParameter("user")//定義登入時,使用者名的 key,預設為 username
                .passwordParameter("pwd") //定義登入時,使用者密碼的 key,預設為 password
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request,
                                                        HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.setContentType("application/json;charset=utf-8");
                        PrintWriter out = response.getWriter();
                        Map<String,Object> map = new HashMap<>();
                        map.put("status",200);
                        map.put("msg",authentication.getPrincipal());
                        //浏覽器傳回json資料
                        out.write(new ObjectMapper().writeValueAsString(map));
                        out.flush();
                        out.close();
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest request,
                                                        HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                        response.setContentType("application/json;charset=utf-8");
                        PrintWriter out = response.getWriter();
                        Map<String,Object> map = new HashMap<>();
                        map.put("status",401);
                        if (e instanceof LockedException){
                            map.put("msg","賬戶被鎖定,登入失敗");
                        }else if (e instanceof BadCredentialsException){
                            map.put("msg","使用者名或密碼輸入錯誤,登入失敗");
                        }else if (e instanceof DisabledException){
                            map.put("msg","賬戶被禁用,登入失敗");
                        }else if(e instanceof AccountExpiredException){
                            map.put("msg","賬戶過期,登入失敗");
                        }else if (e instanceof CredentialsExpiredException){
                            map.put("msg","密碼過期,登入失敗");
                        }else {
                            map.put("msg","登入失敗");
                        }
                        //浏覽器傳回json資料
                        out.write(new ObjectMapper().writeValueAsString(map));
                        out.flush();
                        out.close();
                    }
                })
        .permitAll()    //和表單登入相關的接口統統都直接通過
        .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        Map<String,Object> map = new HashMap<>();
                        map.put("status",200);
                        map.put("msg","登出登入成功");
                        //浏覽器傳回json資料
                        out.write(new ObjectMapper().writeValueAsString(map));
                        out.flush();
                        out.close();
                    }
                })
                .permitAll()
                .and()
        .csrf().disable();
    }
}
           

繼續閱讀