SpringBoot集成Spring Security(一)登錄註銷

SpringBoot集成Spring Security(二)註冊 、密碼加密、修改密碼
寫在前面
Spring Security是一種基於 Spring AOP 和 Servlet 過濾器的安全框架。它提供全面的安全性解決方案,同時在 Web 請求級和方法調用級處理身份確認和授權。
由於最近寫的項目用到了這方面知識,這裏做一些總結。下面直接看代碼
一、創建項目
這裏以多模塊項目爲例。

多模塊項目優點: 幫助項目劃分模塊,鼓勵重用,防止POM變得過於龐大,方便各個模塊的構建,而不用每次都構建整個項目,使得針對某個模塊的特殊控制更爲方便。
在這裏插入圖片描述
二、引入pom依賴

<dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

三、web層

項目最核心的代碼
SecurityConfig.java

/**
 * @author xiao
 * 使用springsecurity對用戶登錄、註銷以及權限進行控制
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private StudentService studentService;

    @Autowired
    private ObjectMapper objectMapper;

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(studentService).passwordEncoder(new BCryptPasswordEncoder());
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
//                .authenticationProvider(authenticationProvider())
                .httpBasic()
                //未登錄時
                .authenticationEntryPoint((request,response,authException) -> {
                    response.setContentType("application/json;charset=utf-8");
                    response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                    PrintWriter out = response.getWriter();
                    RespBean error = RespBean.error("未登錄");
                    String s = new ObjectMapper().writeValueAsString(error);
                    out.write(s);
                    out.flush();
                    out.close();
                })

                .and()
                .authorizeRequests()
                .anyRequest().authenticated() //必須授權才能範圍

                .and()
                .formLogin() //使用自帶的登錄
                .usernameParameter("username")
                .passwordParameter("password")
                .permitAll()
                //登錄失敗,返回json
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException exception) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                        PrintWriter out = resp.getWriter();
                        RespBean respBean = RespBean.error("登錄失敗!");
                        if (exception instanceof UsernameNotFoundException || exception instanceof BadCredentialsException) {
                            respBean.setMsg("用戶名或者密碼輸入錯誤,請重新輸入!");
                        } else if (exception instanceof DisabledException) {
                            respBean.setMsg("賬戶被禁用");
                        } else {
                            respBean.setMsg("未知錯誤");
                        }
                        out.write(objectMapper.writeValueAsString(respBean));
                        out.flush();
                        out.close();
                    }
                })
                //登錄成功,返回json
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        Student student = (Student) authentication.getPrincipal();
                        student.setPassword(null);
                        RespBean ok = RespBean.ok("登錄成功!", student);
                        String s = new ObjectMapper().writeValueAsString(ok);
                        out.write(s);
                        out.flush();
                        out.close();
                    }
                })
                .and()
                .exceptionHandling()
                //沒有權限,返回json
                .accessDeniedHandler((request,response,ex) -> {
                    response.setContentType("application/json;charset=utf-8");
                    response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                    PrintWriter out = response.getWriter();
                    out.write(new ObjectMapper().writeValueAsString(RespBean.error("權限不足")));
                    out.flush();
                    out.close();
                })
                .and()
                .logout()
                //退出成功,返回json
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        out.write(new ObjectMapper().writeValueAsString(RespBean.ok("註銷成功!")));
                        out.flush();
                        out.close();
                    }
                })
                .permitAll();
        //開啓跨域訪問
        http.cors().disable();
        //開啓模擬請求,比如API POST測試工具的測試,不開啓時,API POST爲報403錯誤
        http.csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) {
        //對於在header裏面增加token等類似情況,放行所有OPTIONS請求。
        web.ignoring()
                .antMatchers(HttpMethod.OPTIONS, "/**");
    }
}

四、mapper層

mapper下的StudentMapper.java

/**
 * @author xiao
 */
public interface StudentMapper {

    Student loadUserBySno(String sno);
}

resource下的StudentMapper.xml**

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.jxnu.os.mapper.StudentMapper">
    <resultMap id="BaseResultMap" type="com.jxnu.os.model.Student">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="username" property="username" jdbcType="VARCHAR"/>
        <result column="sno" property="sno" jdbcType="VARCHAR"/>
        <result column="s_sex" property="s_sex" jdbcType="CHAR"/>
        <result column="t_id" property="t_id" jdbcType="INTEGER"/>
        <result column="password" property="password" jdbcType="VARCHAR"/>
    </resultMap>

    <select id="loadUserByUsername" resultMap="BaseResultMap">
        select * from student where username=#{username}
    </select>

</mapper>

五、model層

model下的Student.java
注意一定要implements UserDetails

/**
 * @author xiao
 * 學生實體類
 */
public class Student implements UserDetails {
//
    //學生主鍵ID
    private Integer id;
    //學生姓名
    private String username;
    //登錄密碼
    private String password;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    private Collection<? extends GrantedAuthority> authorities;

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
        this.authorities = authorities;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

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

    @Override
    public String getUsername() {
        return this.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;
    }
}

六、service層
service下的StudentService.java

/**
 * @author xiao
 */
@Service
public class StudentService implements UserDetailsService {

    @Autowired
    StudentMapper studentMapper;

    /**
     * 登錄
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Student student = studentMapper.loadUserBySno(username);
        if (student == null) {
            throw new UsernameNotFoundException("用戶不存在");
        }
        return student;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章