springboot整合任务安全

任务

异步任务

在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的;但是在 处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用 多线程来完成此类任务,其实,在Spring 3.x之后,就已经内置了**@Async**来完 美解决这个问题。

两个注解: @EnableAysnc、@Aysnc

上代码

启动类代码

@EnableAsync
@SpringBootApplication
public class Demo13TaskApplication {

    public static void main(String[] args) {
        SpringApplication.run(Demo13TaskApplication.class, args);
    }

}

service代码

@Service
public class AsyncService {

    /*
    告诉spring这是一个异步方法
     */
    @Async
    public void hello() throws InterruptedException {
        Thread.sleep(3000);
        System.out.println("数据处理中");
    }
}

controller代码

@Controller
public class AsyncController {

    @Autowired
    AsyncService asyncService;

    @ResponseBody
    @GetMapping("/hello")
    public String hello() throws InterruptedException {
        asyncService.hello();
        return "success";
    }
}

只要我们在浏览器中访问hello浏览器会立刻跳转success,服务器会延时打印数据处理

定时任务

项目开发中经常需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前 一天的日志信息。Spring为我们提供了异步执行任务调度的方式,提供 TaskExecutor 、TaskScheduler 接口。

两个注解:@EnableScheduling、@Scheduled

启动类

@EnableScheduling
@SpringBootApplication
public class Demo13TaskApplication {

    public static void main(String[] args) {
        SpringApplication.run(Demo13TaskApplication.class, args);
    }

}

service代码

@Service
public class ScheduledService {
    /**
     * second(秒), minute(分), hour(时), day of month(日), month(月), day of week(周几).
     * 0 * * * * MON-FRI
     *  【0 0/5 14,18 * * ?】 每天14点整,和18点整,每隔5分钟执行一次
     *  【0 15 10 ? * 1-6】 每个月的周一至周六10:15分执行一次
     *  【0 0 2 ? * 6L】每个月的最后一个周六凌晨2点执行一次
     *  【0 0 2 LW * ?】每个月的最后一个工作日凌晨2点执行一次
     *  【0 0 2-4 ? * 1#1】每个月的第一个周一凌晨2点到4点期间,每个整点都执行一次;
     */
    // @Scheduled(cron = "0 * * * * MON-SAT")
    // @Scheduled(cron = "0,1,2,3,4 * * * * MON-SAT")
    // @Scheduled(cron = "0-4 * * * * MON-SAT")
    @Scheduled(cron = "0/4 * * * * MON-SAT")  //每4秒执行一次
    public void hello(){
        System.out.println("hello....");
    }
}

只要我们启动了springboot程序,hello就会每四秒打印一次.

邮件任务

pom文件

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

我们要使用的邮箱一定要在这里获取一下密码

配置文件

spring.mail.username=2590416618@qq.com
spring.mail.password=krfyvrmx
spring.mail.host=smtp.qq.com
spring.mail.properties.mail.smtp.ssl.enable=true

测试一下

@SpringBootTest
class Demo13TaskApplicationTests {

    @Autowired
    JavaMailSenderImpl javaMailSenderImpl;

    @Test
    void contextLoads() {
        //1.创建一个简单的的消息邮件
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setSubject("通知");
        simpleMailMessage.setText("这是通过spring-boot进行邮件通知测试");
        simpleMailMessage.setTo("2590416618@qq.com");
        simpleMailMessage.setFrom("2590416618@qq.com");
        javaMailSenderImpl.send(simpleMailMessage);
    }

    @Test
    void test01() throws  Exception{
        //1.创建一个复杂的消息邮件
        MimeMessage mimeMessage = javaMailSenderImpl.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        helper.setSubject("通知");
        helper.setText("<b style='color:red'>这是通过spring-boot进行复杂邮件通知测试</b>",true);
        helper.setTo("2590416618@qq.com");
        helper.setFrom("2590416618@qq.com");
        helper.addAttachment("1.jpg",new File("C:\\Users\\86157\\Desktop\\小丫头\\1.jpg"));
        javaMailSenderImpl.send(mimeMessage);
    }

}

安全

在spring的安全配置中主要使用的是Spring Security这个框架

如果Spring Security在类路径上,则默认情况下 Web 应用程序是安全的。Spring Boot 依赖 Spring Security 的内容协商策略来确定是否httpBasic使用formLogin. 要为 Web 应用程序添加方法级别的安全性,您还可以添加@EnableGlobalMethodSecurity所需的设置。更多信息可以在Spring Security Reference Guide中找到。

默认UserDetailsService只有一个用户。用户名为user,密码是随机的,在应用程序启动时打印在 INFO 级别,如下例所示:

使用生成的安全密码:78fa095d-3f4c-48b1-ad50-e24c31d5cf35

如果您微调日志配置,请确保将org.springframework.boot.autoconfigure.security类别设置为日志INFO级别消息。否则,不会打印默认密码。

您可以通过提供spring.security.user.name和来更改用户名和密码spring.security.user.password

web安全

默认安全配置在SecurityAutoConfiguration和中实现UserDetailsServiceAutoConfiguration。 为 Web 安全SecurityAutoConfiguration导入并配置身份验证,这在非 Web 应用程序中也相关。要完全关闭默认的 Web 应用程序安全配置或组合多个 Spring Security 组件(例如 OAuth2 客户端和资源服务器),请添加一个类型的 bean (这样做不会禁用配置或执行器的安全性)。

Config文件

@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 定制授权规则
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("VIP1")
                .antMatchers("/level2/**").hasRole("VIP2")
                .antMatchers("/level3/**").hasRole("VIP3");
        //开启登录功能
        http.formLogin()
                .loginPage("/userlogin");
        //1、/login来到登陆页
        //2、重定向到/login?error表示登陆失败
        //3、更多详细规定
        //4、默认post形式的 /login代表处理登陆
        //5、一但定制loginPage;那么 loginPage的post请求就是登陆

        //开启自动配置的登出功能
        http.logout().logoutSuccessUrl("/");//注销成功之后来到首页
        //1.访问/logout表示用户注销

        //开启记住我的功能
        http.rememberMe().rememberMeParameter("remeber");
    }

    //定义认证规则
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder())
                .withUser("zhangsan").password("123456").roles("VIP1","VIP2")
                .and().withUser("lisi").password("123456").roles("VIP1")
                .and().withUser("wangwu").password("123456").roles("VIP3");
    }
}

由于在spring5中密码必须要加入加密策略

我们的加密策略,需要实现PasswordEncoder

@Component
public class MyPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence charSequence) {
        return charSequence.toString();
    }

    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return s.equals(charSequence.toString());
    }
}

controller

@Controller
public class KungfuController {
   private final String PREFIX = "pages/";
   /**
    * 欢迎页
    * @return
    */
   @GetMapping("/")
   public String index() {
      return "welcome";
   }
   
   /**
    * 登陆页
    * @return
    */
   @GetMapping("/userlogin")
   public String loginPage() {
      return PREFIX+"login";
   }
   
   
   /**
    * level1页面映射
    * @param path
    * @return
    */
   @GetMapping("/level1/{path}")
   public String level1(@PathVariable("path")String path) {
      return PREFIX+"level1/"+path;
   }
   
   /**
    * level2页面映射
    * @param path
    * @return
    */
   @GetMapping("/level2/{path}")
   public String level2(@PathVariable("path")String path) {
      return PREFIX+"level2/"+path;
   }
   
   /**
    * level3页面映射
    * @param path
    * @return
    */
   @GetMapping("/level3/{path}")
   public String level3(@PathVariable("path")String path) {
      return PREFIX+"level3/"+path;
   }

}

连接数据库

请添加图片描述请添加图片描述

请添加图片描述

这是我们的数据库

案例还是我们的案例

这次我们连接数据库用到的是jdbc加mybatis

导入依赖

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

配置类

@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 定制授权规则
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("USER")
                .antMatchers("/level2/**").hasRole("ADMIN")
                .antMatchers("/level3/**").hasRole("King");
        //开启登录功能
        http.formLogin()
                .loginPage("/userlogin");
        //1、/login来到登陆页
        //2、重定向到/login?error表示登陆失败
        //3、更多详细规定
        //4、默认post形式的 /login代表处理登陆
        //5、一但定制loginPage;那么 loginPage的post请求就是登陆

        //开启自动配置的登出功能
        http.logout().logoutSuccessUrl("/");//注销成功之后来到首页
        //1.访问/logout表示用户注销

        //开启记住我的功能
        http.rememberMe().rememberMeParameter("remeber");
    }

    @Bean
    UserLoginServiceImpl UserService() { // 注册UserDetailsService 的bean

        return new UserLoginServiceImpl();
    }
    //定义认证规则
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /*auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder())
                .withUser("zhangsan").password("123456").roles("USER")
                .and().withUser("lisi").password("123456").roles("ADMIN")
                .and().withUser("wangwu").password("123456").roles("King");*/
        auth.userDetailsService(UserService())
                .passwordEncoder(new MyPasswordEncoder());
    }

}

一定要用这样的形式

@Bean
UserLoginServiceImpl UserService() { // 注册UserDetailsService 的bean

    return new UserLoginServiceImpl();
}

new的话会出错,刚开始以为是mybatis配置出错,但是在另外一个界面中却是没有错。仔细查看了报错信息发现报了空指针异常后,然后才进行了数据库的连接操作。感觉可能是bean加载的地方出错,查阅了相关资料了,在下面的博主的文章中:https://www.cnblogs.com/shamo89/p/8534580.html得到启发,拦截器运行时候,处于SpringMVC阶段,@Service应该是还没有注入到spring中,在Spring Security配置文件中将原来的代码改回去。问题得到解决。猜测这个应该是在项目运行使用拦截器的时候,提前在spring注入拦截器需要的组件。如果理解有错,希望大佬留言指正!

loginservice类

@Service
public class UserLoginServiceImpl implements UserLoginService {

    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserInfo userinfo = null;
        userinfo = userDao.findByUsername(username);
        System.out.println(userinfo.getUsername());
        User user = new User(userinfo.getUsername(), userinfo.getPassword(), userinfo.getStatus() == 0 ? false : true, true, true, true, getAuthority(userinfo.getRoles()));
        return user;
    }

    private List<SimpleGrantedAuthority> getAuthority(List<Role> roles) {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName()));
        }
        return authorities;
    }
}

User类

@Date
public class UserInfo {
    private String id;
    private String username;
    private String email;
    private String password;
    private String phoneNum;
    private int status;
    private String statusStr;
    private List<Role> roles;
}    

权限类

public class Role {
    private String id;
    private String roleName;
    private String roleDesc;
    private List<Permission> permissions;
    private List<UserInfo> users;
}    

UserDao类

@Component
@Mapper
public interface UserDao {

    @Select("select * from users where username = #{username}")
    @Results(
        @Result(property = "roles",column = "id",javaType = List.class,many = @Many(select = "com.example.demo14sercurity.Mapper.RoleDao.findByUserId"))
    )
    public UserInfo findByUsername(String username);
}    

RoleDao类

@Component
@Mapper
public interface RoleDao {

    @Select("select * from role where id in (select roleId from users_role where userId = #{userId}) ")   
    public List<Role> findByUserId(String userId);
}    

这样我们的数据就连接上我们的安全框架了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值