依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--页面相关包-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
启动类
@SpringBootApplication
@EnableWebSecurity
public class SpringSecurityMain6666 {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityMain6666.class, args);
}
}
两种方式获取账户密码
1、配置类配置账户密码
server.port=9098
spring.application.name=cloud-spring-security-service6666
spring.security.user.name=admin
spring.security.user.password=123456
# 关闭页面缓存方便看效果
spring.thymeleaf.cache=false
2、实现 UserDetailsService 接口
实现 UserDetailsService 接口规范,可以自定义账户密码,可以从数据库或者 redis 取数据。
@Service
public class MyUserDeatilService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println(">>>>>>username="+username);
MyUser user = MyDb.queryUserByName(username);
return Optional.ofNullable(user)
.map(r->{
System.out.println(">>>>>>>>user="+user);
return new User(username,new BCryptPasswordEncoder().encode(user.getPassword()),
// 注意这里角色是 ROLE_xxx 有前缀的哦
AuthorityUtils.commaSeparatedStringToAuthorityList("admin1,ROLE_role11"));
})
.orElseThrow(()->{
System.out.println(">>>>>>>Sorry,没有该用户!");
return new RuntimeException("Sorry,没有该用户!!");
});
}
}
注意:角色需要加上 ROLE_xxx 前缀,比如 role1 角色,需要写成 ROLE_role1,权限名不用直接写 admin1 即可。
3、实现配置类 WebSecurityConfigurerAdapter
SpringSecurity 所有的重要操作都在这。不同的操作可以覆写不同的方法实现
@Configuration
public class MyWebSecurityConfig2 extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private DataSource dataSource;
// 密码加密
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
// 将前端页面传递过来的账户密码保存到数据中
// 实现记住密码的功能
@Autowired
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
return jdbcTokenRepository;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().accessDeniedPage("/no_authen.html");
// 表示准别自定义一些跳转页面
http.formLogin()
// 定义自己的具体登录页面
.loginPage("/userLogin.html")
// 定义表单提交之后交给具体的处理 LoginController
.loginProcessingUrl("/login")
// 当登录成功之后跳转到哪个具体的 IndexController
.defaultSuccessUrl("/helloIndex").permitAll()
// 设置哪些路径可以被放行,不需要认证
.and().authorizeRequests()
.antMatchers("/hello","/login").permitAll()
// 表示当前登录的人必须要有 admin 权限才可以访问 /helloIndex 路径
// 注意 hasAuthority 只能设置单个角色或者是单个权限控制,多个要用 hasAnyAuthority()
// .antMatchers("/helloIndex").hasAuthority("admin1")
// 表单当前这个用户只有具备 admin1/2/3 任意一个权限就可以访问 /helloIndex
.antMatchers("/helloIndex").hasAnyAuthority("admin1","admin2","admin3")
// 表单需要具备 role1 角色才能够访问 /helloIndex
// .antMatchers("/helloIndex").hasRole("role1")
// 表单需要具备 role1/2/3 任意一个角色才能够访问 /helloIndex
// .antMatchers(("/helloIndex")).hasAnyRole("role1","role2","role3")
.anyRequest().authenticated()
.and().rememberMe().tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(60) // 设置有效时长为 60s
.userDetailsService(userDetailsService)
// 关闭 csrf 防护
.and().csrf().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/resources/**");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
其中 hasAnyRole()、hasAnyAuthority() 方法时用来判断当前登录中的用户是否具备哪些权限或者角色,只有具备这些配置的权限或权限才可以登录成功,否则跳转到 no_authen.html 无权限访问页面。
注解替换 hasAnyRole()/hasAnyAuthority() 方法
使用注解来实现权限管控需要开启一个注解 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
@Secured
注解只能用来判断角色,如:
@RequestMapping("/update")
// @Secured 只能用来判断具备哪些角色,不能用来判断权限
@Secured({"ROLE_role11","ROLE_role1"})
public String update() {
return "update 界面.....";
}
当前用户需具备 ROLE_role11、ROLE_role1 角色才可以访问该方法。
@PreAuthorize
注解可以替换 hasAnyRole()/hasAnyAuthority() 方法,如:
@RequestMapping("/update")
// @PreAuthorize("hasRole('ROLE_role12')")
// @PreAuthorize("hasAnyRole('ROLE_role12','ROLE_role11')")
// @PreAuthorize("hasAuthority('admin2')")
@PreAuthorize("hasAnyAuthority('admin1','admin2')")
// TODO @PreAuthorize("hasPermission()")
public String update() {
return "update 界面.....";
}
最后提供一个 JWT 加解密的方式:
@Component
public class MyTokenManager {
private long tokenExpiration = 24*60*60*1000;
private String tokenSignKey = "123456";
public String createToken(String userName) {
return Jwts.builder().setSubject(userName)
.setExpiration(new Date(System.currentTimeMillis() - tokenExpiration))
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
}
public String getTokenSignKey() {
return Jwts.parser().setSigningKey(tokenSignKey)
.parseClaimsJws(tokenSignKey)
.getBody()
.getSubject();
}
}
版权声明:本文为qq_35971258原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。