

设置配置文件
- @Configuration
- public class SecurityConfig extends WebSecurityConfigurerAdapter {
-
- @Bean
- PasswordEncoder passwordEncoder() {
- return NoOpPasswordEncoder.getInstance();}
-
- //认证用户账号和密码
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- auth.inMemoryAuthentication()
- .withUser("admin")
- .password("123456").roles("admin");
- }
-
- //静态资源不拦截
- @Override
- public void configure(WebSecurity web) throws Exception {
- web.ignoring().antMatchers("/js/**", "/css/**","/images/**");
- }
-
- //表单登录设置
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .formLogin()
- .loginPage("/login.html")
- .permitAll()
- .and()
- .csrf()
- .disable();
- }
- }
在 Spring Security 中,如果我们不做任何配置,默认的登录页面和登录接口的地址都是 /login,也就是说,默认会存在如下两个请求:
GET http://localhost:8080/login
POST http://localhost:8080/login
可以通过 loginProcessingUrl 方法来指定登录接口地址 
此时我们还需要修改登录页面里边的 action 属性,改为 /doLogin

设置登录成功重定向:
与登录成功相似,登录失败也是有两个方法:
设置两个账号进行权限实验测试:
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- auth.inMemoryAuthentication()
- .withUser("lm").password("123123").roles("root")
- .and()
- .withUser("admin").password("123456").roles("admin")
- .and()
- .passwordEncoder(new UserPasswordEncoder());
- }
加密UserPasswordEncoder
- public class UserPasswordEncoder implements PasswordEncoder {
-
- @Override
- public String encode(CharSequence charSequence) {
- return charSequence.toString();
- }
-
- @Override
- public boolean matches(CharSequence charSequence, String s) {
- return s.equals(charSequence.toString());
- }
- }
路径权配置
- http
- .authorizeRequests()
- .antMatchers("/lg/admin/**").hasRole("admin")
- .antMatchers("/lg/root/**").hasRole("root")
- .anyRequest().authenticated()
- .and()
- ...
1)「hasAuthority(String)」 判断角色是否具有特定权限
http.authorizeRequests().antMatchers("/main1.html").hasAuthority("admin")
2)「hasAnyAuthority(String ...)」 如果用户具备给定权限中某一个,就允许访问
http.authorizeRequests().antMatchers("/admin/read").hasAnyAuthority("xxx","xxx")
3)「hasRole(String)」 如果用户具备给定角色就允许访问。否则出现403
http.authorizeRequests().antMatchers("/admin/read").hasRole("管理员")
4) 「hasAnyRole(String ...)」 如果用户具备给定角色的任意一个,就允许被访问
http.authorizeRequests().antMatchers("/guest/read").hasAnyRole("管理员", "访客")
5) 「hasIpAddress(String)」 请求是指定的IP就运行访问
http.authorizeRequests().antMatchers("/ip").hasIpAddress("127.0.0.1")
测试demo
- @Controller
- @RequestMapping("/lg")
- public class HelloControl {
-
- @RequestMapping(value = "/index",method = RequestMethod.GET)
- public String userLogin(){
- return "index";
- }
-
- @RequestMapping(value = "/hello",method = RequestMethod.GET)
- @ResponseBody
- public String hello(){
- return "this is hello";
- }
-
- @RequestMapping(value = "/root",method = RequestMethod.GET)
- @ResponseBody
- public String root(){
- return "this is root";
- }
-
- @RequestMapping(value = "/admin",method = RequestMethod.GET)
- @ResponseBody
- public String admin(){
- return "this is admin";
- }
- }
使用lm账号登录测试一下:




Spring Boot默认使用LogBack日志系统,如果不需要更改为其他日志系统如Log4j2等,则无需多余的配置,LogBack默认将日志打印到控制台上。
使用日志功能,只需要在相应类上加上@Slf4j(lambok组件)注解,在对应方法中log.info(),log.error()等就可以输出日志。

![]()
同时可以在application.properties里进行配置,将日志写入本地


1)pom.xml配置
- <dependency>
- <groupId>org.mybatis.spring.bootgroupId>
- <artifactId>mybatis-spring-boot-starterartifactId>
- <version>2.1.2version>
- dependency>
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- <optional>trueoptional>
- dependency>
-
- <dependency>
- <groupId>com.alibabagroupId>
- <artifactId>druid-spring-boot-starterartifactId>
- <version>1.1.21version>
- dependency>
- <dependency>
- <groupId>mysqlgroupId>
- <artifactId>mysql-connector-javaartifactId>
- <scope>runtimescope>
- dependency>
2)application.properties配置
- spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.datasource.url=jdbc:mysql://localhost:3306/springsecurity
- spring.datasource.username=root
- spring.datasource.password=rootlhc
- # 初始化配置
- spring.datasource.druid.initial-size=3
- # 最小连接数
- spring.datasource.druid.min-idle=3
- # 最大连接数
- spring.datasource.druid.max-active=15
- # 获取连接超时时间
- spring.datasource.druid.max-wait=5000
- # 连接有效性检测时间
- spring.datasource.druid.time-between-eviction-runs-millis=90000
- # 最大空闲时间
- spring.datasource.druid.min-evictable-idle-time-millis=1800000
- spring.datasource.druid.test-while-idle=true
- spring.datasource.druid.test-on-borrow=false
- spring.datasource.druid.test-on-return=false
- spring.datasource.druid.validation-query=select 1
- # 配置监控统计拦截的filters
- spring.datasource.druid.filters=stat
- spring.datasource.druid.web-stat-filter.url-pattern=/*
- spring.datasource.druid.web-stat-filter.exclusions="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
- spring.datasource.druid.stat-view-servlet.enabled=true
- spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
- spring.datasource.druid.stat-view-servlet.reset-enable=true
- spring.datasource.druid.stat-view-servlet.login-username=admin
- spring.datasource.druid.stat-view-servlet.login-password=admin
- spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
- spring.jackson.time-zone=GMT+8
- mybatis.type-aliases-package=com.lhc.lhcprojectdemo.util.entity
- mybatis.mapper-locations=classpath:/mappers/*
- mybatis.configuration.map-underscore-to-camel-case=true
3)SysUser设置
SysUser.java
- @Data
- @EqualsAndHashCode(callSuper = true)
- @NoArgsConstructor
- public class SysUser extends BaseEntity{
- private static final long serialVersionUID = -6525908145032868837L;
-
- private Integer userId;
-
- private Integer deptId;
-
- private String userName;
-
- private String password;
-
- private String nickName;
-
- private String phone;
-
- private String email;
-
- private Integer status;
-
- public interface Status {
- int LOCKED = 0;
- int VALID = 1;
- }
- }
UserDao.java
- @Mapper
- public interface UserDao {
- /**
- * 分页返回所有用户
- */
- List
getAllUserByPage(@Param("startPosition")Integer startPosition, @Param("limit")Integer limit); -
- }
UserService.java
- public interface UserService {
- ResultUtil
getAllUsersByPage(Integer startPosition, Integer limit); - }
UserServiceImpl.java
- @Service
- public class UserServiceImpl implements UserService {
- @Autowired
- private UserDao userDao;
-
- @Override
- public ResultUtil
getAllUsersByPage(Integer startPosition, Integer limit) { - return ResultUtil.ok().data(userDao.getAllUserByPage(startPosition,limit)).code(ResultCode.TABLE_SUCCESS);
- }
- }
UseControl.java
- @Controller
- @RequestMapping("/api/user")
- public class UserControl {
- @Autowired
- private UserService userService;
-
- @GetMapping("/index")
- @ResponseBody
- public ResultUtil
index(PageTableRequest pageTableRequest){ - pageTableRequest.countOffset();
- return userService.getAllUsersByPage(pageTableRequest.getOffset(),pageTableRequest.getLimit());
- }
- }
UserMapper.xml
- "1.0" encoding="UTF-8" ?>
- mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.lhc.lhcprojectdemo.dao.UserDao">
-
- <select id="getAllUserByPage" resultType="com.lhc.lhcprojectdemo.util.entity.SysUser">
- SELECT u.user_id,u.dept_id,u.user_name,u.password,u.nick_name,u.phone,u.email,u.status,u.create_time,u.update_time
- FROM sys_user u
- ORDER BY u.user_id
- select>
-
- mapper>
4)测试

5)设置角色和权限
sys_role
sys_menu(可以简单设置sys_permit)
然后关联user- role,menu-role(permit-role)


1)给API添加权限

2)添加security配置注解

3)认证授权
- @Autowired
- private UserDetailsService userDetailsService;
-
- @Bean
- public PasswordEncoder passwordEncoder(){
- return new BCryptPasswordEncoder();
- }
-
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
- }
4)自定义用户信息
- @Data
- @ToString
- public class JwtUserDto implements UserDetails {
- /**
- * 用户数据
- */
- private SysUser myUser;
-
- //private List
roleInfo; - /**
- * 用户权限的集合
- */
- @JsonIgnore
- private List
authorities; -
- public List
getRoles() { - return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
- }
-
-
- /**
- * 加密后的密码
- * @return
- */
- public String getPassword() {
- return myUser.getPassword();
- }
-
-
- /**
- * 用户名
- * @return
- */
- public String getUsername() {
- return myUser.getUserName();
- }
-
-
- /**
- * 是否过期
- * @return
- */
- public boolean isAccountNonExpired() {
- return true;
- }
-
-
- /**
- * 是否锁定
- * @return
- */
- public boolean isAccountNonLocked() {
- return true;
- }
-
-
- /**
- * 凭证是否过期
- * @return
- */
- public boolean isCredentialsNonExpired() {
- return true;
- }
-
-
- /**
- * 是否可用
- * @return
- */
- public boolean isEnabled() {
- return myUser.getStatus() == 1 ? true : false;
- }
-
-
- public JwtUserDto(SysUser sysUser, List
authorities) { - this.myUser = sysUser;
- this.authorities = authorities;
- }
- }
5)自定义一个UserDetailsServiceImpl实现UserDetailsService
- @Service
- @Slf4j
- public class UserDetailsServiceImpl implements UserDetailsService {
-
- @Autowired
- private UserService userService;
- @Autowired
- private RoleService roleService;
- @Autowired
- private RoleUserService roleUserService;
- @Autowired
- private MenuDao menuDao;
-
- @Override
- public JwtUserDto loadUserByUsername(String userName) throws UsernameNotFoundException {
- SysUser user = userService.getUserByName(userName);//根据用户名获取用户
- if (user == null ){
- throw new UsernameNotFoundException("用户名不存在");//这个异常一定要抛
- }else if (user.getStatus().equals(SysUser.Status.LOCKED)) {
- throw new LockedException("用户被锁定,请联系管理员");
- }
- List
grantedAuthorities = new ArrayList<>(); - //菜单表中获取信息
- List
list = menuDao.listByUserId(user.getUserId()); -
- List
collect = list.stream().map(MenuIndexDto::getPermission).collect(Collectors.toList()); - for (String authority : collect){
- if (!("").equals(authority) & authority !=null){
- GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(authority);
- //获取到user:list等具体权限
- grantedAuthorities.add(grantedAuthority);
- }
- }
- JwtUserDto loginUser =new JwtUserDto(user,grantedAuthorities);
- return loginUser;
- }
- }
1)配置pom文件
-
- <dependency>
- <groupId>com.github.whvcsegroupId>
- <artifactId>easy-captchaartifactId>
- <version>1.6.2version>
- dependency>

2)准备验证码生成control
- @Controller
- public class CaptchaController {
-
- @RequestMapping("/captcha")
- public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
- CaptchaUtil.out(120, 45, 4, request, response);
- }
- }
3)login.html登录界面配置验证码
- <div>
- <input id="captcha" name="captcha" size="6" style="width:150px;height:40px" placeholder="验 证 码:" type="text">
- <img src="/captcha" width="130px" height="40px" onclick="this.src=this.src+'?'+Math.random()" title="点击刷新"/>
- div>
4)验证码校验
- @Component
- public class VerifyCodeFilter extends OncePerRequestFilter {
- private String defaultFilterProcessUrl = "/dologin";
- private String method = "POST";
-
- @Override
- protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
- if (method.equalsIgnoreCase(request.getMethod()) && defaultFilterProcessUrl.equals(request.getServletPath())) {
- // 登录请求校验验证码,非登录请求不用校验
- HttpSession session = request.getSession();
- String requestCaptcha = request.getParameter("captcha");
- //验证码的信息存放在seesion种,具体看EasyCaptcha官方解释
- String genCaptcha = (String) request.getSession().getAttribute("captcha");
- response.setContentType("application/json;charset=UTF-8");
- if (requestCaptcha.isEmpty()){
- //删除缓存里的验证码信息
- session.removeAttribute("captcha");
- response.getWriter().write(JSON.toJSONString(ResultUtil.error().message("验证码不能为空!")));
- return;
- }
- if (genCaptcha.isEmpty()){
- response.getWriter().write(JSON.toJSONString(ResultUtil.error().message("验证码已失效!")));
- return;
- }
- if (!genCaptcha.equalsIgnoreCase(requestCaptcha)){
- session.removeAttribute("captcha");
- response.getWriter().write(JSON.toJSONString(ResultUtil.error().message("验证码错误!")));
- return;
- }
- }
- chain.doFilter(request, response);
- }
- }
5)security配置
