SpringSecurity简单使用

Updated on with 0 views and 0 comments

POM依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>

从数据库中验证信息并进行简单的权限验证

自定义UserDetail

@Data
public class User implements UserDetails {

    private Integer id;

    private String username;

    private String password;

    private Long gmtCreate;

    private Long gmtModified;

    private String avatarUrl;

    private Integer vipLevel;

    private String vipName;

    private Boolean status;

    private String name;

    private Integer sex;

    private String description;

    private List<Role> roleList = new ArrayList();

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

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

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

自定义GrantedAuthority

@Data
public class Role implements GrantedAuthority {
    private Integer id;

    private String name;

    private String description;

    @Override
    public String getAuthority() {
        return name;
    }
}

实现UserDetailsService接口

重新写loadUserByUsername方法

@Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserExample example = new UserExample();
        example.createCriteria().andUsernameEqualTo(username);
        com.wu.manager.pojo.User user = userMapper.selectByExample(example).get(0);
        user.getVipLevel();
        UserGrade userGrade = userGradeMapper.selectByPrimaryKey(user.getVipLevel());
        user.setVipName(userGrade.getGradeName());
        if (user == null) return null;
        List<Role> authorities = authorities(user.getId());
        user.setRoleList(authorities);
        return user;
    }

    //给当前用户指定角色
    private List<Role> authorities(Integer id) {
        List<Role> authorities = new ArrayList<>();
        UserRoleExample userRoleExample = new UserRoleExample();
        userRoleExample.createCriteria().andUserIdEqualTo(id);
        List<UserRole> userRoleList = userRoleMapper.selectByExample(userRoleExample);
        for (UserRole userRole : userRoleList) {
            Role role = roleMapper.selectByPrimaryKey(userRole.getRoleId());
            authorities.add(role);
        }
        return authorities;
    }

自定义配置类

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,jsr250Enabled = true,securedEnabled = true)    //开权限方法权限注解支持
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;
    @Autowired
    private DataSource dataSource;

    @Bean
    public PasswordEncoder createPwdEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl persistentTokenRepository = new JdbcTokenRepositoryImpl();
        persistentTokenRepository.setDataSource(dataSource);
        return persistentTokenRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()    //对登录请求放行
                .antMatchers("/res/**").permitAll()
                .antMatchers("/index/**").hasAnyAuthority("VIP")
                .antMatchers("/**")   //拦截根目录以及根目录下的子目录
                .fullyAuthenticated()  //对所有的资源进行请求拦截
                .and()
                .formLogin()   //以表单验证的方式对所有的拦截资源进行认证
                .loginPage("/login")   //自定义登录页面
//                .successForwardUrl("/")  //登录成功后的跳转页面
                .successHandler(new MyAuthenticationSuccessHandler())  //登录成功返回json信息
                .failureHandler(new MyAuthenticationFailureHandler())  //登录失败返回json信息
                .and()
                .rememberMe().tokenValiditySeconds(86400)
                .and()
                .logout().deleteCookies("remember-me")
        .and().headers().frameOptions().sameOrigin()
        .and().sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry());
//                .csrf().disable()   //关闭跨域访问
        ;
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }
}

登陆成功返回json

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        httpServletResponse.setContentType("application/json;charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();
        out.write(JsonUtils.objectToJson(LayUIResult.build(200,"登陆成功")));
        out.flush();
        out.close();
    }
}

登陆失败返回json

public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        httpServletResponse.setContentType("application/json;charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();
        out.write(JsonUtils.objectToJson(LayUIResult.build(400,"登录失败")));
        out.flush();
        out.close();
    }
}

自定义login页面

 @RequestMapping("/login")
    public String login() {
        return "/page/login/login";
    }

权限验证

springboot配置类形式,在SpringSecurity配置类上添加注解

@EnableGlobalMethodSecurity(prePostEnabled = true,jsr250Enabled = true,securedEnabled = true)    //开权限方法权限注解支持

在controller或者service上开启权限控制

//@PreAuthorize("hasRole('ROLE_MANAGER')")
@Secured({"ROLE_MANAGER","ROLE_USER"})
@RolesAllowed({"ROLE_USER","ROLE_MANAGER"})

只需要开启一个即可,可以实现对controller等的权限控制

csrf跨域访问

跨域访问保护默认是开启的,这时你的登陆、退出必须为POST方式,以及增删改必须携带CSRF令牌

方式一:form表单中携带隐藏令牌

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
$.ajax({
            type: "POST",
            url: "/login",
            data: $('#loginForm').serialize(),
            dataType: "json",
            success: function (loginCallback) {
                if (loginCallback.code == '200') {
                    layer.msg("登录成功", {
                        icon: 6,
                        time: 1000 //2秒关闭(如果不配置,默认是3秒)
                    }, function () {    //弹框后的操作
                        window.location.href = "/";
                    });
                } else {
                    layer.msg("用户名或密码错误,请重新输入", {
                        icon: 2,
                        time: 2000 //2秒关闭(如果不配置,默认是3秒)
                    });
                }
            },
            error: function (jqXHR) {
                layer.alert("发生错误:" + jqXHR.status, {
                    title: 'Error'
                });
            }
        });

方式二:头信息中携带

  <meta name="_csrf" th:content="${_csrf.token}"/>
  <meta name="_csrf_header" th:content="${_csrf.headerName}">
//ajax请求时都带上csrf信息
    $(function () {
        var token = $("meta[name='_csrf']").attr("content")
        var header = $("meta[name='_csrf_header']").attr("content")
        $(document).ajaxSend(function (e, xhr, options) {
        xhr.setRequestHeader(header,token)
        })
    })