在SpringBoot项目中使用SpringSecurity权限认证框架

来源:互联网 发布:conoha 网络 编辑:程序博客网 时间:2024/06/05 04:17
当前两大权限认证框架:shiro和Spring Security
SpringBoot版本:1.5.8

1.在SpringBoot中欲使用Spring Security,首先需要添加依赖:
<!--声明使用Spring security的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>
2.在Application的Properties文件中,配置:
#Spring Security config
logging.level.org.springframework.security=info
3.写一个Security的Java配置类:
package com.kgoos.app.configure;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
importorg.springframework.security.config.annotation.web.builders.HttpSecurity;
importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
importorg.springframework.security.core.userdetails.UserDetailsService;
@Configuration
public classWebSecurityConfig extendsWebSecurityConfigurerAdapter {
@Bean
UserDetailsService customUserService() {//2
return newSysUserServiceImpl();
}
@Override
protected voidconfigure(AuthenticationManagerBuilder auth)throws Exception {
auth.userDetailsService(customUserService());
}
@Override
protected voidconfigure(HttpSecurity http) throwsException {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error")
.permitAll()
.and()
.logout().permitAll();
}
}
在SpringMVC中也添加配置:
@Configuration
public classMyWebConfig extendsWebMvcConfigurerAdapter {
@Override
public voidaddViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
4.准备SpringSecurity认证需要的两个实体类:SysRoleSysUser
import lombok.Getter;
importlombok.Setter;
importjavax.persistence.Entity;
importjavax.persistence.GeneratedValue;
importjavax.persistence.Id;
importjava.io.Serializable;
/**
* Description:This PO is used for system auth :Spring Security
*@authordbdu
*@date17-12-21 上午9:34
*/
@Entity
@Getter@Setter
public classSysRole implementsSerializable { //注意此处要实现序列化接口,否则终端执行会出错!
@Id
@GeneratedValue
privateLong id;
privateString name;

}
------------------------------------------
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
importjavax.persistence.CascadeType;
importjavax.persistence.Entity;
importjavax.persistence.FetchType;
importjavax.persistence.GeneratedValue;
importjavax.persistence.Id;
importjavax.persistence.ManyToMany;
importlombok.Getter;
importlombok.Setter;
importorg.springframework.security.core.GrantedAuthority;
importorg.springframework.security.core.authority.SimpleGrantedAuthority;
importorg.springframework.security.core.userdetails.UserDetails;

@Entity
@Getter@Setter
public classSysUserimplements UserDetails { //1
private static final longserialVersionUID= 1L;
@Id
@GeneratedValue
privateLong id;
privateString username;
privateString password; //当然若是实际项目中使用,可能会有其他更多的属性.
@ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.EAGER)
privateList<SysRole> roles;
@Override
publicCollection<? extendsGrantedAuthority> getAuthorities() {//2
List<GrantedAuthority> auths =new ArrayList<GrantedAuthority>();
List<SysRole> roles =this.getRoles();
for(SysRole role : roles) {
auths.add(newSimpleGrantedAuthority(role.getName()));
}
returnauths;
}
@Override
public booleanisAccountNonExpired() {
return true;
}
@Override
public booleanisAccountNonLocked() {
return true;
}
@Override
public booleanisCredentialsNonExpired() {
return true;
}
@Override
public booleanisEnabled() {
return true;
}
}
5.准备实体对应的repository和Service
import com.kgoos.app.entity.SysUser;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SysUserRepositoryextends JpaRepository<SysUser, Long> {
SysUser findByUsername(String username);
}
---------------------------------------
import com.kgoos.app.entity.SysUser;
importcom.kgoos.app.repository.SysUserRepository;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.security.core.userdetails.UserDetails;
importorg.springframework.security.core.userdetails.UserDetailsService;
importorg.springframework.security.core.userdetails.UsernameNotFoundException;
@Service
public classSysUserServiceImpl implementsISysUserService { //1
@Autowired
SysUserRepositoryuserRepository;
@Override
publicUserDetails loadUserByUsername(String username) {//2
SysUser user =userRepository.findByUsername(username);
if(user ==null){
throw newUsernameNotFoundException("用户名不存在");
}
returnuser; //3
}
}

/**
* Description:此处继承仅是为了让代码看起来更加规范而已
* Created at:2017-12-21 10:12,
* by dbdu
*/
public interfaceISysUserService extendsUserDetailsService {}
6.向数据表中插入基本的数据:
insert into SYS_USER (id,username, password) values (1,'dbdu', 'dbdu');
insert into SYS_USER (id,username, password) values (2,'dusuanyun', 'dusuanyun');
insert into SYS_ROLE(id,name) values(1,'ROLE_ADMIN');
insert into SYS_ROLE(id,name) values(2,'ROLE_USER');
insert into SYS_USER_ROLES(SYS_USER_ID,ROLES_ID) values(1,1);
insert into SYS_USER_ROLES(SYS_USER_ID,ROLES_ID) values(2,2);
7.注意login和logout的url是固定的,为/login和/logout,不需要专门为这两个url写控制器!!

8.准备login.html和home.html的thymeleaf文件放置在,resources--templates目录下.

9.详细信息,参考KGoos项目的security_test_branch分支,此分支配置了此框架的认证方式.

疑问1:如何根据角色不同,区分什么是admin的,什么是普通用户的?
解答:
方式一:使用thymeleaf有方式可以判断角色
A.先引入命名空间:<htmlxmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
B.使用hasRole('ROLE_ADMIN')"来判断角色:
<divsec:authorize="hasRole('ROLE_ADMIN')">
<pclass="bg-info"th:text="${msg.etraInfo}"></p>
</div>
方式二:使用异步Ajax的方式
如果前端需要角色信息来决定显示什么页面,可以考虑提供控制器将用户信息以Json的方式给前端!
疑问2:如何添加用户?
解决:利用Hibernate的映射关系存储关联关系!
疑问3:如何使用密码的密文? ---现在存储的是明文
解决:
第一步:自己定义一个密码编码解码的类实现PasswordEncoder接口
/**
* Description: 这个类是专为使用SpringSecurity认证框架设计的,用户处理密码是明码还是密码的问题!
* Created at:2017-12-21 14:18,
* by dbdu
*/
public classMD5PasswordEncoder implementsPasswordEncoder {
@Override
publicString encode(CharSequence charSequence) {
returnMD5Util.encode((String) charSequence);
}
@Override
public booleanmatches(CharSequence rawPassword, String encodedPassword) {
if(null!= encodedPassword && encodedPassword.equals(encode(rawPassword))) {
return true;
}
return false;
}
}
第二步:在WebSecurityConfig类中,增加自定义的编码解码器,例如:
@Configuration
public classWebSecurityConfig extendsWebSecurityConfigurerAdapter {
@Bean
UserDetailsService customUserService() {//2
return newSysUserServiceImpl();
}
@Override
protected voidconfigure(AuthenticationManagerBuilder auth)throws Exception {
//指定密码的编码和解码方式:MD5PasswordEncoder
auth.userDetailsService(customUserService()).passwordEncoder(new MD5PasswordEncoder());
//auth.userDetailsService(sysUserService);
}
@Override
protected voidconfigure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error")
.permitAll()
.and()
.logout().permitAll();
}
}
疑问4:如何将登录的用户,用户名显示在页面上,其实就是如何获取已经登录成功的用户的信息
解决:没有测试过
A.JSP的方式:principal 用户的基本信息对象
B.Thymeleaf的方式:
方式一:使用表达式实用程序对象
#authentication对象可以很容易地使用,就像这样:
<divth:text = “ $ {#authentication.name} ” > 认证对象的“name”属性的值应该出现在这里。 </div >
方式二:使用sec:authentication属性相当于使用#authentication对象,但使用自己的属性:
<divsec:authentication = “ name ” > 认证对象的“name”属性的值应该出现在这里。 </div >
更多的内容参见:https://github.com/thymeleaf/thymeleaf-extras-springsecurity 英语不好的朋友可以用谷歌浏览器右键翻译
C.自己的思路:
登录成功后,发请求,然后将请求到的数据直接存到session会话里,写一个监听器session注销的时候,清除保存在session里的数据,当然你要是不管它好像也没什么问题.

参考资料:
A.<<JavaEE开发的颠覆者-SpringBoot实战>>,第九章第一节
B.<<Spring实战第四版中文版>>,第九章
C.参考链接:https://github.com/thymeleaf/thymeleaf-extras-springsecurity


阅读全文
0 0
原创粉丝点击