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

当前两大权限认证框架: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;
import org.springframework.context.annotation. Bean ;
import org.springframework.context.annotation. Configuration ;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
UserDetailsService customUserService() { //2
return new SysUserServiceImpl();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserService());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage( "/login" )
.failureUrl( "/login?error" )
.permitAll()
.and()
.logout().permitAll();
}
}
在SpringMVC中也添加配置:
@Configuration
public class MyWebConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController( "/login" ).setViewName( "login" );
}
}
4.准备SpringSecurity认证需要的两个实体类: SysRoleSysUser
import lombok. Getter ;
import lombok. Setter ;
import javax.persistence. Entity ;
import javax.persistence. GeneratedValue ;
import javax.persistence. Id ;
import java.io.Serializable;
/**
* Description:This PO is used for system auth :Spring Security
* @author dbdu
* @date 17-12-21 上午9:34
*/
@Entity
@Getter@Setter
public class SysRole implements Serializable { //注意此处要实现序列化接口,否则终端执行会出错!
@Id
@GeneratedValue
private Long id ;
private String name ;

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

@Entity
@Getter@Setter
public class SysUser implements UserDetails { //1
private static final long serialVersionUID = 1L ;
@Id
@GeneratedValue
private Long id ;
private String username ;
private String password ; //当然若是实际项目中使用,可能会有其他更多的属性.
@ManyToMany (cascade = {CascadeType. REFRESH }, fetch = FetchType. EAGER )
private List<SysRole> roles ;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() { //2
List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
List<SysRole> roles = this .getRoles();
for (SysRole role : roles) {
auths.add( new SimpleGrantedAuthority(role.getName()));
}
return auths;
}
@Override
public boolean isAccountNonExpired() {
return true ;
}
@Override
public boolean isAccountNonLocked() {
return true ;
}
@Override
public boolean isCredentialsNonExpired() {
return true ;
}
@Override
public boolean isEnabled() {
return true ;
}
}
5.准备实体对应的repository和Service
import com.kgoos.app.entity.SysUser;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SysUserRepository extends JpaRepository<SysUser, Long> {
SysUser findByUsername(String username);
}
---------------------------------------
import com.kgoos.app.entity.SysUser;
import com.kgoos.app.repository.SysUserRepository;
import org.springframework.beans.factory.annotation. Autowired ;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
@Service
public class SysUserServiceImpl implements ISysUserService { //1
@Autowired
SysUserRepository userRepository ;
@Override
public UserDetails loadUserByUsername(String username) { //2
SysUser user = userRepository .findByUsername(username);
if (user == null ){
throw new UsernameNotFoundException( "用户名不存在" );
}
return user; //3
}
}

/**
* Description:此处继承仅是为了让代码看起来更加规范而已
* Created at:2017-12-21 10:12,
* by dbdu
*/
public interface ISysUserService extends UserDetailsService {}
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.先引入命名空间: < html xmlns: th = "http://www.thymeleaf.org"
xmlns: sec = "http://www.thymeleaf.org/thymeleaf-extras-springsecurity4" >
B.使用 hasRole('ROLE_ADMIN')" 来判断角色:
< div sec :authorize= "hasRole('ROLE_ADMIN')" >
< p class= "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 class MD5PasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
return MD5Util. encode ((String) charSequence);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if ( null != encodedPassword && encodedPassword.equals(encode(rawPassword))) {
return true ;
}
return false ;
}
}
第二步:在 WebSecurityConfig类中,增加自定义的编码解码器,例如:
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
UserDetailsService customUserService() { //2
return new SysUserServiceImpl();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//指定密码的编码和解码方式:MD5PasswordEncoder
auth.userDetailsService(customUserService()) .passwordEncoder(new MD5PasswordEncoder());
//auth.userDetailsService(sysUserService);
}
@Override
protected void configure(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 对象可以很容易地使用,就像这样:
< div th:text = “ $ {#authentication.name} ” > 认证对象的“name”属性的值应该出现在这里。 </ div >
方式二:使用 sec:authentication 属性相当于使用 #authentication 对象,但使用自己的属性:
< div sec:authentication = “ name ” > 认证对象的“name”属性的值应该出现在这里。 </ div >
更多的内容参见: https://github.com/thymeleaf/thymeleaf-extras-springsecurity 英语不好的朋友可以用谷歌浏览器右键翻译
C.自己的思路:
登录成功后,发请求,然后将请求到的数据直接存到session会话里,写一个监听器session注销的时候,清除保存在session里的数据,当然你要是不管它好像也没什么问题.

参考资料:
A.<<JavaEE开发的颠覆者-SpringBoot实战>>,第九章第一节
B.<<Spring实战第四版中文版>>,第九章


猜你喜欢

转载自blog.csdn.net/dusuanyun/article/details/78864257